Implement revealable animation on hover

This commit is contained in:
Dennis Schoepf 2021-08-01 17:38:38 +02:00
parent 8ad126c8d8
commit f98c3e58dc
5 changed files with 107 additions and 28 deletions

9
package-lock.json generated
View file

@ -1235,6 +1235,12 @@
"integrity": "sha512-WUjeFT2SXd6intfE6cg6eL1jk/JL88JqM2gC4WqO4iHLmbCvHUq6aoLK13lGpDWs4FtS2PHoYraJZ0dEx99Dyg==", "integrity": "sha512-WUjeFT2SXd6intfE6cg6eL1jk/JL88JqM2gC4WqO4iHLmbCvHUq6aoLK13lGpDWs4FtS2PHoYraJZ0dEx99Dyg==",
"dev": true "dev": true
}, },
"@types/lodash": {
"version": "4.14.171",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.171.tgz",
"integrity": "sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg==",
"dev": true
},
"@types/p5": { "@types/p5": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/@types/p5/-/p5-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/p5/-/p5-1.3.0.tgz",
@ -4215,8 +4221,7 @@
"lodash": { "lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"dev": true
}, },
"lodash.clone": { "lodash.clone": {
"version": "4.5.0", "version": "4.5.0",

View file

@ -12,6 +12,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/animejs": "^3.1.4", "@types/animejs": "^3.1.4",
"@types/lodash": "^4.14.171",
"@types/p5": "^1.3.0", "@types/p5": "^1.3.0",
"parcel-bundler": "^1.12.5", "parcel-bundler": "^1.12.5",
"prettier": "^2.3.2", "prettier": "^2.3.2",
@ -20,6 +21,7 @@
}, },
"dependencies": { "dependencies": {
"animejs": "^3.2.1", "animejs": "^3.2.1",
"lodash": "^4.17.21",
"p5": "^1.4.0", "p5": "^1.4.0",
"rxjs": "^7.2.0", "rxjs": "^7.2.0",
"zustand": "^3.5.7" "zustand": "^3.5.7"

View file

@ -1,3 +1,4 @@
import _ from 'lodash';
import { mp5 } from '../../main'; import { mp5 } from '../../main';
import { colors } from '../constants/colors'; import { colors } from '../constants/colors';
import { generateRevealableCoords } from '../helpers'; import { generateRevealableCoords } from '../helpers';
@ -15,7 +16,8 @@ export class DetailScene {
constructor() { constructor() {
this.player = new Player(); this.player = new Player();
store.subscribe((state) => { store.subscribe((state, prevState) => {
if (!_.isEqual(state.revealables, prevState.revealables)) {
this.revealables = state.revealables; this.revealables = state.revealables;
this.revealableCoords = generateRevealableCoords(); this.revealableCoords = generateRevealableCoords();
this.revealableObjects = this.revealables.map( this.revealableObjects = this.revealables.map(
@ -26,6 +28,9 @@ export class DetailScene {
w: this.revealables[i].size, w: this.revealables[i].size,
}) })
); );
}
// TODO: Check if everything was found, if so, get back to overview screen
}); });
} }

View file

@ -2,6 +2,7 @@ import { combineLatest } from 'rxjs';
import { mp5 } from '../../main'; import { mp5 } from '../../main';
import { areasColliding, playerHead$, revealedArea$ } from '../area'; import { areasColliding, playerHead$, revealedArea$ } from '../area';
import { colors } from '../constants/colors'; import { colors } from '../constants/colors';
import store from '../store';
import { Area } from '../types'; import { Area } from '../types';
export enum RevealableTypes { export enum RevealableTypes {
@ -24,22 +25,42 @@ enum RevealableStates {
HIDDEN = 'HIDDEN', HIDDEN = 'HIDDEN',
REVEALED = 'REVEALED', REVEALED = 'REVEALED',
FOUND = 'FOUND', FOUND = 'FOUND',
INACTIVE = 'INACTIVE',
} }
export class Revealable { export class Revealable {
state: RevealableStates = RevealableStates.HIDDEN; state: RevealableStates = RevealableStates.HIDDEN;
area: Area; area: Area;
type: RevealableTypes;
name: string;
path: string;
contents: string;
url: string;
imageUrl: string;
isHovered: boolean; isHovered: boolean;
isRevealed: boolean; isRevealed: boolean;
wasInteractedWith: boolean;
minSize: number = 5; minSize: number = 5;
currentSize: number; currentSize: number;
maxSize: number; maxSize: number;
pulseCurrentSize: number;
pulseOpacity: number = 255;
pulseCountUp: boolean;
constructor({ type, name, path, contents, url, imageUrl }: RevealableInterface, area: Area) { constructor({ type, name, path, contents, url, imageUrl }: RevealableInterface, area: Area) {
this.type = type;
this.name = name;
this.path = path;
this.contents = contents;
this.url = url;
this.imageUrl = imageUrl;
this.area = area; this.area = area;
this.currentSize = this.minSize; this.currentSize = this.minSize;
this.pulseCurrentSize = area.w;
this.maxSize = area.w; this.maxSize = area.w;
combineLatest([revealedArea$, playerHead$]).subscribe(([revealedArea, playerHead]) => { combineLatest([revealedArea$, playerHead$]).subscribe(([revealedArea, playerHead]) => {
@ -54,6 +75,9 @@ export class Revealable {
w: this.currentSize, w: this.currentSize,
}); });
if (this.wasInteractedWith) {
this.state = RevealableStates.INACTIVE;
} else {
if ( if (
((isRevealed && isHovered) || (!isRevealed && isHovered)) && ((isRevealed && isHovered) || (!isRevealed && isHovered)) &&
(this.state === RevealableStates.REVEALED || this.state === RevealableStates.FOUND) (this.state === RevealableStates.REVEALED || this.state === RevealableStates.FOUND)
@ -64,6 +88,7 @@ export class Revealable {
} else { } else {
this.state = RevealableStates.HIDDEN; this.state = RevealableStates.HIDDEN;
} }
}
this.isHovered = this.state === RevealableStates.FOUND ? isHovered : false; this.isHovered = this.state === RevealableStates.FOUND ? isHovered : false;
this.isRevealed = isRevealed; this.isRevealed = isRevealed;
@ -79,14 +104,27 @@ export class Revealable {
mp5.fill(mp5.color(colors.greyLight)); mp5.fill(mp5.color(colors.greyLight));
mp5.ellipse(this.area.x, this.area.y, this.currentSize); mp5.ellipse(this.area.x, this.area.y, this.currentSize);
} else if (this.state === RevealableStates.FOUND) { } else if (this.state === RevealableStates.FOUND) {
mp5.fill(mp5.color(colors.redDark)); this.pulsate();
mp5.fill(mp5.color(colors.red));
mp5.ellipse(this.area.x, this.area.y, this.currentSize);
} else if (this.state === RevealableStates.INACTIVE) {
this.reduceSize();
mp5.fill(mp5.color(colors.greyDark));
mp5.ellipse(this.area.x, this.area.y, this.currentSize); mp5.ellipse(this.area.x, this.area.y, this.currentSize);
} }
} }
public onClick() { public onClick() {
if (this.isHovered) { if (this.isHovered && !this.wasInteractedWith) {
console.log('Clicked on Revealable'); console.log('Clicked on Revealable');
this.wasInteractedWith = true;
store.getState().addInfoMessage({
headline: this.name,
innerHTML: this.contents,
});
} }
} }
@ -106,5 +144,33 @@ export class Revealable {
} }
} }
private pulsate() {} private pulsate() {
const minPulse = this.currentSize;
const maxPulse = this.currentSize + 40;
let color: any = mp5.color(colors.red);
console.log(this.pulseCurrentSize, this.pulseCountUp);
if (this.pulseCountUp) {
this.pulseCurrentSize += 1;
this.pulseOpacity = this.pulseOpacity > 255 ? 255 : this.pulseOpacity - 6;
if (this.pulseCurrentSize > maxPulse) {
this.pulseCountUp = false;
}
} else {
this.pulseCurrentSize -= 6;
if (this.pulseCurrentSize < minPulse) {
this.pulseCountUp = true;
this.pulseOpacity = 255;
}
}
color.setAlpha(this.pulseOpacity);
mp5.fill(mp5.color(color));
mp5.ellipse(this.area.x, this.area.y, this.pulseCurrentSize);
}
} }

View file

@ -26,15 +26,16 @@ const store = create<State>(
infoMessageShown: false, infoMessageShown: false,
infoMessages: [], infoMessages: [],
addInfoMessage: (newMessage) => addInfoMessage: (newMessage) =>
set((state) => ({ infoMessages: [...state.infoMessages, newMessage] })), set((state) => ({ ...state, infoMessages: [...state.infoMessages, newMessage] })),
userMessages: [], userMessages: [],
addUserMessage: (newMessage) => addUserMessage: (newMessage) =>
set((state) => ({ userMessages: [...state.userMessages, newMessage] })), set((state) => ({ ...state, userMessages: [...state.userMessages, newMessage] })),
revealables: [], revealables: [],
setProjectMetadata: (projectName) => setProjectMetadata: (projectName) =>
set({ set((state) => ({
...state,
revealables: getRevealablesforSubproject(projectName, project.subprojects), revealables: getRevealablesforSubproject(projectName, project.subprojects),
}), })),
})) }))
); );