add buttons for pencil mode

This commit is contained in:
HF 2024-01-22 06:20:10 +01:00
parent eb6c1772db
commit 236e83694b
10 changed files with 378 additions and 307 deletions

View File

@ -9,6 +9,7 @@ import CoolDownBox from './CoolDownBox';
import NotifyBox from './NotifyBox';
import GlobeButton from './buttons/GlobeButton';
import PalselButton from './buttons/PalselButton';
import PencilButton from './buttons/PencilButton';
import MovementControls from './buttons/MovementControls';
import Palette from './Palette';
import Alert from './Alert';
@ -35,7 +36,10 @@ const UI = () => {
<PalselButton />
<Palette />
{(!is3D) && <GlobeButton />}
{(isOnMobile) && <MovementControls />}
{// (isOnMobile) && <MovementControls />
}
<MovementControls />
{(!is3D) && <PencilButton />}
<CoolDownBox />
</>
)}

View File

@ -17,7 +17,7 @@ const ExpandMenuButton = () => {
return (
<div
id="menubutton"
className="actionbuttons"
className={`actionbuttons${menuOpen ? ' pressed' : ''}`}
role="button"
title={(menuOpen) ? t`Close Menu` : t`Open Menu`}
tabIndex={-1}

View File

@ -4,6 +4,7 @@
*/
import React from 'react';
import { useSelector, shallowEqual } from 'react-redux';
import { getRenderer } from '../../ui/rendererFactory';
@ -11,213 +12,189 @@ const btnStyle = {
fontSize: 34,
};
function move(action, bool) {
const renderer = getRenderer();
switch (action) {
case 'FORWARD': {
renderer.controls.moveForward = bool;
break;
}
case 'BACKWARD': {
renderer.controls.moveBackward = bool;
break;
}
case 'LEFT': {
renderer.controls.moveLeft = bool;
break;
}
case 'RIGHT': {
renderer.controls.moveRight = bool;
break;
}
case 'UP': {
renderer.controls.moveUp = bool;
break;
}
case 'DOWN': {
renderer.controls.moveDown = bool;
break;
}
default:
break;
}
}
function cancelMovement() {
const renderer = getRenderer();
renderer.controls.moveForward = false;
renderer.controls.moveBackward = false;
renderer.controls.moveLeft = false;
renderer.controls.moveRight = false;
renderer.controls.moveUp = false;
renderer.controls.moveDown = false;
renderer.controls.moveU = 0;
renderer.controls.moveV = 0;
renderer.controls.moveW = 0;
}
const MovementControls = () => (
<div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 46,
left: 57,
// bottom: 128,
bottom: 139,
}}
onMouseDown={() => {
move('FORWARD', true);
}}
onMouseUp={() => {
move('FORWARD', false);
}}
onTouchStart={() => {
move('FORWARD', true);
}}
onTouchEnd={() => {
move('FORWARD', false);
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 46,
left: 57,
bottom: 98,
}}
onMouseDown={() => {
move('BACKWARD', true);
}}
onMouseUp={() => {
move('BACKWARD', false);
}}
onTouchStart={() => {
move('BACKWARD', true);
}}
onTouchEnd={() => {
move('BACKWARD', false);
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
left: 16,
bottom: 98,
}}
onMouseDown={() => {
move('LEFT', true);
}}
onMouseUp={() => {
move('LEFT', false);
}}
onTouchStart={() => {
move('LEFT', true);
}}
onTouchEnd={() => {
move('LEFT', false);
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 76,
left: 98,
bottom: 98,
}}
onMouseDown={() => {
move('RIGHT', true);
}}
onMouseUp={() => {
move('RIGHT', false);
}}
onTouchStart={() => {
move('RIGHT', true);
}}
onTouchEnd={() => {
move('RIGHT', false);
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 76,
left: 16,
bottom: 139,
}}
onMouseDown={() => {
move('UP', true);
}}
onMouseUp={() => {
move('UP', false);
}}
onTouchStart={() => {
move('UP', true);
}}
onTouchEnd={() => {
move('UP', false);
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 76,
left: 98,
bottom: 139,
}}
onMouseDown={() => {
move('DOWN', true);
}}
onMouseUp={() => {
move('DOWN', false);
}}
onTouchStart={() => {
move('DOWN', true);
}}
onTouchEnd={() => {
move('DOWN', false);
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
</div>
);
const MovementControls = () => {
const [pencilEnabled, is3D] = useSelector((state) => [
state.gui.pencilEnabled,
state.canvas.is3D,
], shallowEqual);
if (!pencilEnabled && !is3D) {
return null;
}
return (
<>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 46,
left: 57,
// bottom: 128,
bottom: 139,
}}
onMouseDown={() => {
getRenderer().controls.moveV = -1;
}}
onMouseUp={() => {
getRenderer().controls.moveV = 0;
}}
onTouchStart={() => {
getRenderer().controls.moveV = -1;
}}
onTouchEnd={() => {
getRenderer().controls.moveV = 0;
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 46,
left: 57,
bottom: 98,
}}
onMouseDown={() => {
getRenderer().controls.moveV = 1;
}}
onMouseUp={() => {
getRenderer().controls.moveV = 0;
}}
onTouchStart={() => {
getRenderer().controls.moveV = 1;
}}
onTouchEnd={() => {
getRenderer().controls.moveV = 0;
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
left: 16,
bottom: 98,
}}
onMouseDown={() => {
getRenderer().controls.moveU = -1;
}}
onMouseUp={() => {
getRenderer().controls.moveU = 0;
}}
onTouchStart={() => {
getRenderer().controls.moveU = -1;
}}
onTouchEnd={() => {
getRenderer().controls.moveU = 0;
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 76,
left: 98,
bottom: 98,
}}
onMouseDown={() => {
getRenderer().controls.moveU = 1;
}}
onMouseUp={() => {
getRenderer().controls.moveU = 0;
}}
onTouchStart={() => {
getRenderer().controls.moveU = 1;
}}
onTouchEnd={() => {
getRenderer().controls.moveU = 0;
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 76,
left: 16,
bottom: 139,
}}
onMouseDown={() => {
getRenderer().controls.moveW = -1;
}}
onMouseUp={() => {
getRenderer().controls.moveW = 0;
}}
onTouchStart={() => {
getRenderer().controls.moveW = -1;
}}
onTouchEnd={() => {
getRenderer().controls.moveW = 0;
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
<div
className="actionbuttons"
role="button"
tabIndex={0}
style={{
...btnStyle,
// left: 76,
left: 98,
bottom: 139,
}}
onMouseDown={() => {
getRenderer().controls.moveW = 1;
}}
onMouseUp={() => {
getRenderer().controls.moveW = 0;
}}
onTouchStart={() => {
getRenderer().controls.moveW = 1;
}}
onTouchEnd={() => {
getRenderer().controls.moveW = 0;
}}
onTouchCancel={cancelMovement}
onMouseLeave={cancelMovement}
>
</div>
</>
);
};
export default MovementControls;

View File

@ -21,7 +21,7 @@ const PalselButton = () => {
return (
<div
id="palselbutton"
className={`actionbuttons ${(paletteOpen) ? '' : 'pressed'}`}
className={`actionbuttons${(paletteOpen) ? ' pressed' : ''}`}
style={{
color: palette.isDark(selectedColor) ? 'white' : 'black',
backgroundColor: palette.colors[selectedColor],

View File

@ -0,0 +1,30 @@
/**
*
*/
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { TbPencil, TbPencilMinus } from 'react-icons/tb';
import { t } from 'ttag';
import { togglePencil } from '../../store/actions';
const PencilButton = () => {
const pencilEnabled = useSelector((state) => state.gui.pencilEnabled);
const dispatch = useDispatch();
return (
<div
id="pencilbutton"
className={`actionbuttons${pencilEnabled ? ' pressed' : ''}`}
role="button"
title={(pencilEnabled) ? t`Disable Pencil` : t`Enable Pencil`}
tabIndex={-1}
onClick={() => dispatch(togglePencil())}
>
{pencilEnabled ? <TbPencilMinus /> : <TbPencil />}
</div>
);
};
export default React.memo(PencilButton);

View File

@ -43,6 +43,11 @@ class PixelPainterControls {
* 2: right shift
*/
holdPainting = 0;
// if we are moving
moveU = 0;
moveV = 0;
moveW = 0;
prevTime = Date.now();
// if we are waiting before placing pixel via holdPainting again
coolDownDelta = false;
@ -82,9 +87,6 @@ class PixelPainterControls {
document.removeEventListener('keyup', this.onKeyUp, false);
}
// eslint-disable-next-line class-methods-use-this
update() {}
gotCoolDownDelta(delta) {
this.coolDownDelta = true;
setTimeout(() => {
@ -367,7 +369,7 @@ class PixelPainterControls {
this.renderer.storeViewInState();
}
move(direction) {
step(direction) {
const [x, y, scale] = this.renderer.view;
const [dx, dy] = direction.map((z) => z * 100.0 / scale);
this.renderer.updateView([x + dx, y + dy]);
@ -511,6 +513,38 @@ class PixelPainterControls {
}
onKeyUp(event) {
/*
* key locations
*/
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
this.moveV = 0;
return;
case 'ArrowLeft':
case 'KeyA':
this.moveU = 0;
return;
case 'ArrowDown':
case 'KeyS':
this.moveV = 0;
return;
case 'ArrowRight':
case 'KeyD':
this.moveU = 0;
return;
case 'KeyE':
this.moveW = 0;
return;
case 'KeyQ':
this.moveW = 0;
return;
default:
}
/*
* key char
*/
switch (event.key) {
case 'Shift':
case 'CapsLock':
@ -527,7 +561,6 @@ class PixelPainterControls {
) {
return;
}
const { store } = this;
/*
* key location
@ -535,25 +568,25 @@ class PixelPainterControls {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
this.move([0, -1]);
this.moveV = -1;
return;
case 'ArrowLeft':
case 'KeyA':
this.move([-1, 0]);
this.moveU = -1;
return;
case 'ArrowDown':
case 'KeyS':
this.move([0, 1]);
this.moveV = 1;
return;
case 'ArrowRight':
case 'KeyD':
this.move([1, 0]);
this.moveU = 1;
return;
case 'KeyE':
this.zoom(1);
this.moveW = 1;
return;
case 'KeyQ':
this.zoom(-1);
this.moveW = -1;
return;
default:
}
@ -570,6 +603,7 @@ class PixelPainterControls {
return;
case 'Control':
case 'Shift': {
const { store } = this;
const state = store.getState();
const { hover } = state.canvas;
if (hover) {
@ -605,6 +639,33 @@ class PixelPainterControls {
default:
}
}
update() {
let time = Date.now();
const { moveU, moveV, moveW } = this;
if (!(moveU || moveV || moveW)) {
this.prevTime = time;
return false;
}
// set to time since last tick
time -= this.prevTime;
this.prevTime += time;
const [x, y, scale] = this.renderer.view;
const directionalStep = time * 0.4 / scale;
let scaleFactor = scale >= 1.0 ? 1.0005 : 1.0003;
scaleFactor **= moveW;
this.renderer.updateView([
x + directionalStep * moveU,
y + directionalStep * moveV,
scale * scaleFactor ** time,
]);
return true;
}
}
export default PixelPainterControls;

View File

@ -103,12 +103,9 @@ class VoxelPainterControls {
spherical = new Spherical();
sphericalDelta = new Spherical();
//
moveLeft = false;
moveRight = false;
moveForward = false;
moveBackward = false;
moveUp = false;
moveDown = false;
moveU = 0;
moveV = 0;
moveW = 0;
//
scale = 1;
panOffset = new Vector3();
@ -421,67 +418,58 @@ class VoxelPainterControls {
return;
}
switch (event.keyCode) {
case 38: // up
case 87: // w
this.moveForward = true;
break;
case 37: // left
case 65: // a
this.moveLeft = true;
break;
case 40: // down
case 83: // s
this.moveBackward = true;
break;
case 39: // right
case 68: // d
this.moveRight = true;
break;
case 69: // E
this.moveUp = true;
break;
case 67: // C
this.moveDown = true;
break;
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
this.moveV = -1;
return;
case 'ArrowLeft':
case 'KeyA':
this.moveU = -1;
return;
case 'ArrowDown':
case 'KeyS':
this.moveV = 1;
return;
case 'ArrowRight':
case 'KeyD':
this.moveU = 1;
return;
case 'KeyE':
this.moveW = 1;
return;
case 'KeyQ':
this.moveW = -1;
return;
default:
break;
}
}
onDocumentKeyUp(event) {
// ignore key presses if modal is open or chat is used
if (event.target.nodeName === 'INPUT'
|| event.target.nodeName === 'TEXTAREA'
) {
return;
}
switch (event.keyCode) {
case 38: // up
case 87: // w
this.moveForward = false;
break;
case 37: // left
case 65: // a
this.moveLeft = false;
break;
case 40: // down
case 83: // s
this.moveBackward = false;
break;
case 39: // right
case 68: // d
this.moveRight = false;
break;
case 69: // E
this.moveUp = false;
break;
case 67: // C
this.moveDown = false;
break;
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
this.moveV = 0;
return;
case 'ArrowLeft':
case 'KeyA':
this.moveU = 0;
return;
case 'ArrowDown':
case 'KeyS':
this.moveV = 0;
return;
case 'ArrowRight':
case 'KeyD':
this.moveU = 0;
return;
case 'KeyE':
this.moveW = 0;
return;
case 'KeyQ':
this.moveW = 0;
return;
default:
break;
}
}
@ -688,27 +676,22 @@ class VoxelPainterControls {
}
update(force) {
const {
moveRight,
moveLeft,
moveUp,
moveDown,
moveForward,
moveBackward,
} = this;
const time = Date.now();
const { moveU, moveV, moveW } = this;
if (!(force
|| this.state !== STATE.NONE
|| this.forceNextUpdate
|| moveRight || moveLeft
|| moveUp || moveDown
|| moveForward || moveBackward
|| moveU || moveV || moveW
)) {
this.prevTime = Date.now();
this.prevTime = time;
return false;
}
this.forceNextUpdate = false;
const delta = (time - this.prevTime) / 1000.0;
this.prevTime = time;
const {
camera,
target,
@ -720,9 +703,7 @@ class VoxelPainterControls {
panOffset,
sphericalDelta,
} = this;
const time = Date.now();
const delta = (time - this.prevTime) / 1000.0;
velocity.x -= velocity.x * 40.0 * delta;
velocity.y -= velocity.y * 40.0 * delta;
velocity.z -= velocity.z * 40.0 * delta;
@ -731,20 +712,12 @@ class VoxelPainterControls {
velocity.set(0, 0, 0);
}
direction.x = Number(moveRight) - Number(moveLeft);
direction.y = Number(moveUp) - Number(moveDown);
direction.z = Number(moveForward) - Number(moveBackward);
direction.set(moveU, -moveW, -moveV);
direction.normalize();
if (moveLeft || moveRight) {
velocity.x -= direction.x * 1000.0 * delta;
}
if (moveUp || moveDown) {
velocity.y -= direction.y * 1000.0 * delta;
}
if (moveForward || moveBackward) {
velocity.z -= direction.z * 1000.0 * delta;
}
if (moveU) velocity.x -= direction.x * 1000.0 * delta;
if (moveW) velocity.y -= direction.y * 1000.0 * delta;
if (moveV) velocity.z -= direction.z * 1000.0 * delta;
vec.setFromMatrixColumn(camera.matrix, 0);
vec.crossVectors(camera.up, vec);
@ -755,8 +728,6 @@ class VoxelPainterControls {
vec.multiplyScalar(-velocity.x * delta);
panOffset.add(vec);
this.prevTime = time;
offset.copy(camera.position).sub(target);
// rotate offset to "y-axis-is-up" space

View File

@ -93,6 +93,12 @@ export function toggleOpenPalette() {
};
}
export function togglePencil() {
return {
type: 's/TGL_PENCIL',
};
}
export function selectStyle(style) {
return {
type: 's/SELECT_STYLE',

View File

@ -6,6 +6,7 @@ const initialState = {
isLightGrid: false,
compactPalette: false,
paletteOpen: true,
pencilEnabled: false,
mute: false,
chatNotify: true,
// top-left button menu
@ -78,6 +79,13 @@ export default function gui(
};
}
case 's/TGL_PENCIL': {
return {
...state,
pencilEnabled: !state.pencilEnabled,
};
}
case 's/TGL_OPEN_MENU': {
return {
...state,
@ -121,6 +129,12 @@ export default function gui(
chatNotify: !state.chatNotify,
};
case 'persist/REHYDRATE':
return {
...state,
pencilEnabled: false,
};
default:
return state;
}

View File

@ -460,6 +460,14 @@ tr:nth-child(even) {
bottom: 16px;
right: 57px;
}
#pencilbutton {
bottom: 98px;
left: 16px;
transition: bottom 300ms ease-in-out;
}
#pencilbutton.pressed {
bottom: 180px;
}
#historyselect {
position: fixed;