fun: inventory + bag
This commit is contained in:
parent
f197658199
commit
c45d24b909
|
@ -91,6 +91,9 @@ class ItemProxy {
|
|||
get icon() {
|
||||
return this.json.icon;
|
||||
}
|
||||
get label() {
|
||||
return this.json.label;
|
||||
}
|
||||
get projection() {
|
||||
return this.json.projection;
|
||||
}
|
||||
|
|
54
app/react/components/dom/bag.jsx
Normal file
54
app/react/components/dom/bag.jsx
Normal file
|
@ -0,0 +1,54 @@
|
|||
import styles from './bag.module.css';
|
||||
import Slot from './slot.jsx';
|
||||
|
||||
/**
|
||||
* Inventory bag. 10-40 slots of inventory.
|
||||
*/
|
||||
export default function Bag({
|
||||
isInventoryOpen,
|
||||
slots,
|
||||
}) {
|
||||
const Slots = slots.map((slot, i) => (
|
||||
<div
|
||||
className={
|
||||
[styles.slotWrapper]
|
||||
.filter(Boolean).join(' ')
|
||||
}
|
||||
key={i}
|
||||
>
|
||||
<Slot
|
||||
icon={slot?.icon}
|
||||
// onMouseDown={(event) => {
|
||||
// onActivate(i)
|
||||
// event.stopPropagation();
|
||||
// }}
|
||||
// onMouseUp={(event) => {
|
||||
// event.stopPropagation();
|
||||
// }}
|
||||
// onDragOver={(event) => {
|
||||
// event.preventDefault();
|
||||
// }}
|
||||
// onDragStart={(event) => {
|
||||
// if (!slot) {
|
||||
// event.preventDefault();
|
||||
// }
|
||||
// event.dataTransfer.setData('silphius/item', i);
|
||||
// onActivate(i);
|
||||
// }}
|
||||
// onDrop={(event) => {
|
||||
// event.preventDefault();
|
||||
// onActivate(i);
|
||||
// }}
|
||||
qty={slot?.qty}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
return (
|
||||
<div
|
||||
className={styles.bag}
|
||||
style={isInventoryOpen ? {transition: 'none'} : {left: '-440px'}}
|
||||
>
|
||||
{Slots}
|
||||
</div>
|
||||
);
|
||||
}
|
31
app/react/components/dom/bag.module.css
Normal file
31
app/react/components/dom/bag.module.css
Normal file
|
@ -0,0 +1,31 @@
|
|||
.bag {
|
||||
align-self: left;
|
||||
--border: calc(var(--unit) * 3px);
|
||||
background-color: rgba(02, 02, 28, 0.6);
|
||||
border: var(--border) solid #444444;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
left: calc(var(--unit) * 20px);
|
||||
line-height: 0;
|
||||
position: absolute;
|
||||
top: calc(var(--unit) * 90px);
|
||||
transition: left 150ms;
|
||||
max-width: 430.5px;
|
||||
}
|
||||
|
||||
.slotWrapper {
|
||||
border: var(--border) solid #999999;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
line-height: 0;
|
||||
padding: 0;
|
||||
&:not(:nth-child(10n)) {
|
||||
border-right: none;
|
||||
}
|
||||
&:not(:nth-last-of-type(-n+10)) {
|
||||
border-bottom: none;
|
||||
}
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
|
@ -9,8 +9,3 @@
|
|||
user-select: text;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Cookbook";
|
||||
src: url("/assets/fonts/Cookbook.woff") format("woff");
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
background-color: #00000044;
|
||||
border: 1px solid #333333;
|
||||
color: #ffffff;
|
||||
font-family: "Cookbook";
|
||||
font-family: Cookbook, Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 16px;
|
||||
margin: 4px;
|
||||
padding: 0;
|
||||
|
|
|
@ -2,8 +2,3 @@
|
|||
font-family: Cookbook, Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Cookbook";
|
||||
src: url("/assets/fonts/Cookbook.woff") format("woff");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,12 @@ import Slot from './slot.jsx';
|
|||
/**
|
||||
* The hotbar. 10 slots of inventory with an active selection.
|
||||
*/
|
||||
export default function Hotbar({active, onActivate, slots}) {
|
||||
export default function Hotbar({
|
||||
active,
|
||||
hotbarIsHidden,
|
||||
onActivate,
|
||||
slots,
|
||||
}) {
|
||||
const Slots = slots.map((slot, i) => (
|
||||
<div
|
||||
className={
|
||||
|
@ -43,7 +48,9 @@ export default function Hotbar({active, onActivate, slots}) {
|
|||
return (
|
||||
<div
|
||||
className={styles.hotbar}
|
||||
style={hotbarIsHidden ? {top: '-50px'} : {transition: 'none'}}
|
||||
>
|
||||
<p className={styles.label}>{slots[active] && slots[active].label}</p>
|
||||
{Slots}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
.hotbar {
|
||||
align-self: center;
|
||||
align-self: left;
|
||||
--border: calc(var(--unit) * 3px);
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
background-color: rgba(02, 02, 57, 0.6);
|
||||
border: var(--border) solid #444444;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
left: calc(var(--unit) * 20px);
|
||||
line-height: 0;
|
||||
position: absolute;
|
||||
top: calc(var(--unit) * 25px);
|
||||
top: calc(var(--unit) * 20px);
|
||||
transition: top 150ms;
|
||||
}
|
||||
|
||||
.label {
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
font-family: Cookbook, Georgia, 'Times New Roman', Times, serif;
|
||||
left: 50%;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
text-shadow:
|
||||
0px -1px 0px black,
|
||||
1px 0px 0px black,
|
||||
0px 1px 0px black,
|
||||
-1px 0px 0px black
|
||||
;
|
||||
top: -17.5px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.slotWrapper {
|
||||
|
|
|
@ -11,6 +11,7 @@ import addKeyListener from './add-key-listener.js';
|
|||
import ClientEcs from './client-ecs.js';
|
||||
import Disconnected from './dom/disconnected.jsx';
|
||||
import Chat from './dom/chat/chat.jsx';
|
||||
import Bag from './dom/bag.jsx';
|
||||
import Dom from './dom/dom.jsx';
|
||||
import Entities from './dom/entities.jsx';
|
||||
import HotBar from './dom/hotbar.jsx';
|
||||
|
@ -18,6 +19,11 @@ import Pixi from './pixi/pixi.jsx';
|
|||
import Devtools from './devtools.jsx';
|
||||
import styles from './ui.module.css';
|
||||
|
||||
const KEY_MAP = {
|
||||
keyDown: 1,
|
||||
keyUp: 0,
|
||||
};
|
||||
|
||||
function emptySlots() {
|
||||
return Array(10).fill(undefined);
|
||||
}
|
||||
|
@ -50,6 +56,9 @@ function Ui({disconnected}) {
|
|||
const [chatHistoryCaret, setChatHistoryCaret] = useState(-1);
|
||||
const [chatMessages, setChatMessages] = useState({});
|
||||
const [pendingMessage, setPendingMessage] = useState('');
|
||||
const [hotbarIsHidden, setHotbarIsHidden] = useState(true);
|
||||
const [hotbarHideHandle, setHotbarHideHandle] = useState();
|
||||
const [isInventoryOpen, setIsInventoryOpen] = useState(false);
|
||||
useEffect(() => {
|
||||
async function setEcsStuff() {
|
||||
const {default: Components} = await import('@/ecs/components/index.js');
|
||||
|
@ -76,6 +85,44 @@ function Ui({disconnected}) {
|
|||
clearTimeout(handle);
|
||||
};
|
||||
}, [disconnected]);
|
||||
useEffect(() => {
|
||||
return addKeyListener(document.body, ({type, payload}) => {
|
||||
if (chatInputRef.current) {
|
||||
chatInputRef.current.focus();
|
||||
}
|
||||
if (chatIsOpen) {
|
||||
return;
|
||||
}
|
||||
let actionPayload;
|
||||
switch (payload) {
|
||||
case 'w': {
|
||||
actionPayload = {type: 'moveUp', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
actionPayload = {type: 'moveLeft', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
actionPayload = {type: 'moveDown', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
actionPayload = {type: 'moveRight', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (actionPayload) {
|
||||
client.send({
|
||||
type: 'Action',
|
||||
payload: actionPayload,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [
|
||||
chatIsOpen,
|
||||
client,
|
||||
]);
|
||||
useEffect(() => {
|
||||
return addKeyListener(document.body, ({event, type, payload}) => {
|
||||
if ('Escape' === payload && 'keyDown' === type && chatIsOpen) {
|
||||
|
@ -88,10 +135,6 @@ function Ui({disconnected}) {
|
|||
if (chatIsOpen) {
|
||||
return;
|
||||
}
|
||||
const KEY_MAP = {
|
||||
keyDown: 1,
|
||||
keyUp: 0,
|
||||
};
|
||||
let actionPayload;
|
||||
switch (payload) {
|
||||
case '-':
|
||||
|
@ -123,26 +166,25 @@ function Ui({disconnected}) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
actionPayload = {type: 'moveUp', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
actionPayload = {type: 'moveLeft', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
actionPayload = {type: 'moveDown', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
actionPayload = {type: 'moveRight', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case ' ': {
|
||||
actionPayload = {type: 'use', value: KEY_MAP[type]};
|
||||
break;
|
||||
}
|
||||
case 'Tab': {
|
||||
if ('keyDown' === type) {
|
||||
if (isInventoryOpen) {
|
||||
setHotbarIsHidden(true);
|
||||
}
|
||||
else {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
}
|
||||
setIsInventoryOpen(!isInventoryOpen);
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'Enter': {
|
||||
if ('keyDown' === type) {
|
||||
setChatIsOpen(true);
|
||||
|
@ -161,60 +203,150 @@ function Ui({disconnected}) {
|
|||
}
|
||||
case '1': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 1};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '2': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 2};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '3': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 3};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '4': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 4};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '5': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 5};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '6': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 6};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '7': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 7};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '8': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 8};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '9': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 9};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '0': {
|
||||
if ('keyDown' === type) {
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
actionPayload = {type: 'changeSlot', value: 10};
|
||||
}
|
||||
break;
|
||||
|
@ -227,7 +359,17 @@ function Ui({disconnected}) {
|
|||
});
|
||||
}
|
||||
});
|
||||
}, [chatIsOpen, client, debug, devtoolsIsOpen, monopolizers, setDebug, setScale]);
|
||||
}, [
|
||||
chatIsOpen,
|
||||
client,
|
||||
debug,
|
||||
devtoolsIsOpen,
|
||||
hotbarHideHandle,
|
||||
isInventoryOpen,
|
||||
monopolizers,
|
||||
setDebug,
|
||||
setScale,
|
||||
]);
|
||||
usePacket('EcsChange', async () => {
|
||||
setEcs(new ClientEcs({Components, Systems}));
|
||||
setMainEntity(undefined);
|
||||
|
@ -387,6 +529,15 @@ function Ui({disconnected}) {
|
|||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
if (!isInventoryOpen) {
|
||||
setHotbarIsHidden(false);
|
||||
if (hotbarHideHandle) {
|
||||
clearTimeout(hotbarHideHandle);
|
||||
}
|
||||
setHotbarHideHandle(setTimeout(() => {
|
||||
setHotbarIsHidden(true);
|
||||
}, 4000));
|
||||
}
|
||||
if (event.deltaY > 0) {
|
||||
client.send({
|
||||
type: 'Action',
|
||||
|
@ -411,6 +562,7 @@ function Ui({disconnected}) {
|
|||
<Dom>
|
||||
<HotBar
|
||||
active={activeSlot}
|
||||
hotbarIsHidden={hotbarIsHidden}
|
||||
onActivate={(i) => {
|
||||
client.send({
|
||||
type: 'Action',
|
||||
|
@ -419,6 +571,10 @@ function Ui({disconnected}) {
|
|||
}}
|
||||
slots={hotbarSlots}
|
||||
/>
|
||||
<Bag
|
||||
isInventoryOpen={isInventoryOpen}
|
||||
slots={Array(30).fill(undefined)}
|
||||
/>
|
||||
<Entities
|
||||
camera={camera}
|
||||
scale={scale}
|
||||
|
|
|
@ -26,3 +26,8 @@ body {
|
|||
border-radius: 20px;
|
||||
border: 3px solid #333;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Cookbook";
|
||||
src: url("/assets/fonts/Cookbook.woff") format("woff");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"icon": "/assets/brush/brush.png",
|
||||
"label": "Brush",
|
||||
"start": "/assets/brush/start.js"
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"icon": "/assets/hoe/icon.png",
|
||||
"label": "Hoe",
|
||||
"projectionCheck": "/assets/hoe/projection-check.js",
|
||||
"projection": {
|
||||
"distance": [3, -1],
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"icon": "/assets/potion/icon.png",
|
||||
"label": "Potion",
|
||||
"start": "/assets/potion/start.js"
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"icon": "/assets/tomato-seeds/icon.png",
|
||||
"label": "Tomato Seeds",
|
||||
"projection": {
|
||||
"distance": [1, -1],
|
||||
"grid": [
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"icon": "/assets/watering-can/icon.png",
|
||||
"label": "Watering Can",
|
||||
"projectionCheck": "/assets/watering-can/projection-check.js",
|
||||
"projection": {
|
||||
"distance": [3, -1],
|
||||
|
|
Loading…
Reference in New Issue
Block a user