Skip to content

Commit

Permalink
Merge pull request #61 from jaspal007/main
Browse files Browse the repository at this point in the history
Add Custom Maps
  • Loading branch information
webdevcody authored Oct 17, 2024
2 parents 7ee9936 + f39812f commit cb10626
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 0 deletions.
90 changes: 90 additions & 0 deletions app/games/[gameId]/visualizer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Button } from "@/components/ui/button";
import { ZombieSurvival } from "@/simulators/zombie-survival";
import { useEffect, useRef, useState } from "react";

const REPLAY_SPEED = 600;

export function Visualizer({
map,
autoStart = false,
onSimulationEnd,
}: {
map: string[][];
autoStart?: boolean;
onSimulationEnd?: (isWin: boolean) => void;
}) {
const simulator = useRef<ZombieSurvival | null>(null);
const interval = useRef<NodeJS.Timeout | null>(null);
const [isRunning, setIsRunning] = useState(false);
const [mapState, setMapState] = useState(map);
const [needsReset, setNeedsReset] = useState(false);

const startSimulation = () => {
setNeedsReset(true);
const clonedMap = JSON.parse(JSON.stringify(map));
simulator.current = new ZombieSurvival(clonedMap);
setMapState(simulator.current!.getState());
setIsRunning(true);
interval.current = setInterval(() => {
if (simulator.current!.finished()) {
clearInterval(interval.current!);
interval.current = null;
setIsRunning(false);
if (onSimulationEnd) {
console.log("here");
onSimulationEnd(!simulator.current!.getPlayer().dead());
}
return;
}
simulator.current!.step();
setMapState(simulator.current!.getState());
}, REPLAY_SPEED);
};

useEffect(() => {
if (autoStart) {
startSimulation();
}
}, [autoStart]);

useEffect(() => {
return () => {
if (interval.current) {
clearInterval(interval.current);
}
};
}, []);

return (
<div>
{mapState.map((row, y) => (
<div key={y} className="flex ">
{row.map((cell, x) => (
<div
key={x}
className={`size-8 border flex items-center justify-center text-2xl`}
>
{cell}
</div>
))}
</div>
))}
<div className="flex gap-2 justify-center py-2">
<Button onClick={startSimulation} disabled={isRunning}>
Replay
</Button>
<Button
disabled={isRunning}
onClick={() => {
simulator.current = new ZombieSurvival(map);
setMapState(simulator.current!.getState());
setIsRunning(false);
setNeedsReset(false);
}}
>
Reset
</Button>
</div>
</div>
);
}
5 changes: 5 additions & 0 deletions app/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export default function Header() {
<Link href="/leaderboard">
<Button variant="ghost">Leaderboard</Button>
</Link>
{isAuthenticated && (
<Link href="/maps">
<Button variant="ghost">Add custom Maps</Button>
</Link>
)}
{flags?.showTestPage && (
<Link href="/test">
<Button variant="ghost">Test</Button>
Expand Down
173 changes: 173 additions & 0 deletions app/maps/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
"use client";

import { Input } from "@/components/ui/input";
import React, { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { useMutation } from "convex/react";
import { api } from "@/convex/_generated/api";

export default function AddMapPage() {
const [height, setHeight] = useState(1);
const [width, setWidth] = useState(1);
const [map, setMap] = useState<string[][]>([]);
const [isSubmitted, setIsSubmitted] = useState(false);
const [isZombie, setIsZombie] = useState(false);
const createMap = useMutation(api.maps.addMap);
useEffect(() => {
generateMap();
}, [height, width]);

const generateMap = () => {
const newMap = Array.from({ length: height }, () =>
Array.from({ length: width }, () => " "),
);
newMap.forEach((row, y) => {
row.forEach((cell, x) => {
newMap[y][x] = " ";
});
});
setMap(newMap);
};
const checkValidMap = () => {
var flag = false;
map.forEach((row, y) => {
row.forEach((cell, x) => {
if (map[y][x] == " ") {
console.log("All well!");
flag = true;
}
});
});
console.log(map);
if (!flag) {
console.log("All set");
console.log(map);
alert("No place left to place the player!");
}else{
createMap({grid: map});
alert("Map saved");
}
};
const setCell = (y: number, x: number, z: boolean) => {
var cell = " ";
if (z == true) {
if (map[y][x] == "Z") {
cell = " ";
} else {
cell = "Z";
}
} else {
if (map[y][x] == "B") {
cell = " ";
} else {
cell = "B";
}
}
const newMap = map.map((row) => [...row]);
newMap[y][x] = cell;
setMap(newMap);
};
return (
<div className="flex-col container mx-auto">
{isSubmitted ? (
<div>
<div className="flex justify-center m-5">
<Button
className="mx-2"
variant={isZombie ? "default" : "outline"}
onClick={() => setIsZombie(true)}
>
Place Zombie
</Button>
<Button
className="mx-2"
variant={isZombie ? "outline" : "default"}
onClick={() => setIsZombie(false)}
>
Place Block
</Button>
</div>
<div className="justify-center m-5">
{map.map((row, y) => (
<div key={y} className="flex justify-center">
{row.map((cell, x) => (
<div
key={x}
className={`size-8 border flex items-center justify-center text-2xl p-5`}
>
<Button
className="m-5"
variant="outline"
onClick={() => {
setCell(y, x, isZombie);
}}
>
{map[y][x]}
</Button>
</div>
))}
</div>
))}
</div>
</div>
) : (
<div>
<h1>Enter the height of the map: </h1>
<Input
type="number"
value={height}
onChange={(e) => {
setHeight(+e.target.value);
}}
/>
<h1>Enter the width of the map: </h1>
<Input
type="number"
value={width}
onChange={(e) => {
setWidth(+e.target.value);
}}
/>
<div className="justify-center m-5">
{map.map((row, y) => (
<div key={y} className="flex justify-center">
{row.map((cell, x) => (
<div
key={x}
className={`size-8 border flex items-center justify-center text-2xl`}
>
{cell}
</div>
))}
</div>
))}
</div>
</div>
)}
<div className="flex justify-center m-5">
{isSubmitted ? (
<div>
<Button className="mx-2" type="submit" onClick={checkValidMap}>
Save map
</Button>
<Button
className="mx-2"
variant="destructive"
onClick={() => {
setIsSubmitted(false);
map.fill([]);
generateMap();
}}
>
Reset
</Button>
</div>
) : (
<Button type="submit" onClick={() => setIsSubmitted(true)}>
Confirm grid
</Button>
)}
</div>
</div>
);
}
14 changes: 14 additions & 0 deletions convex/maps.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
internalAction,
internalMutation,
mutation,
query,
action,
} from "./_generated/server";
Expand Down Expand Up @@ -37,6 +38,19 @@ const LEVELS = [
},
];

export const addMap = mutation({
args: {
grid: v.array(v.array(v.string())),
},
handler: async(ctx, args)=>{
const arr = ctx.db.query("maps").collect();
await ctx.db.insert("maps", {
level: (await arr).length+1,
grid: args.grid,
});
}
});

export const seedMaps = internalMutation({
handler: async (ctx) => {
const maps = await ctx.db.query("maps").collect();
Expand Down

0 comments on commit cb10626

Please sign in to comment.