Implement revealable animation on hover
This commit is contained in:
parent
8ad126c8d8
commit
f98c3e58dc
5 changed files with 107 additions and 28 deletions
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -1235,6 +1235,12 @@
|
|||
"integrity": "sha512-WUjeFT2SXd6intfE6cg6eL1jk/JL88JqM2gC4WqO4iHLmbCvHUq6aoLK13lGpDWs4FtS2PHoYraJZ0dEx99Dyg==",
|
||||
"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": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/p5/-/p5-1.3.0.tgz",
|
||||
|
|
@ -4215,8 +4221,7 @@
|
|||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.clone": {
|
||||
"version": "4.5.0",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/animejs": "^3.1.4",
|
||||
"@types/lodash": "^4.14.171",
|
||||
"@types/p5": "^1.3.0",
|
||||
"parcel-bundler": "^1.12.5",
|
||||
"prettier": "^2.3.2",
|
||||
|
|
@ -20,6 +21,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"animejs": "^3.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"p5": "^1.4.0",
|
||||
"rxjs": "^7.2.0",
|
||||
"zustand": "^3.5.7"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import _ from 'lodash';
|
||||
import { mp5 } from '../../main';
|
||||
import { colors } from '../constants/colors';
|
||||
import { generateRevealableCoords } from '../helpers';
|
||||
|
|
@ -15,17 +16,21 @@ export class DetailScene {
|
|||
constructor() {
|
||||
this.player = new Player();
|
||||
|
||||
store.subscribe((state) => {
|
||||
this.revealables = state.revealables;
|
||||
this.revealableCoords = generateRevealableCoords();
|
||||
this.revealableObjects = this.revealables.map(
|
||||
(revealable, i) =>
|
||||
new Revealable(revealable, {
|
||||
x: this.revealableCoords[i].x,
|
||||
y: this.revealableCoords[i].y,
|
||||
w: this.revealables[i].size,
|
||||
})
|
||||
);
|
||||
store.subscribe((state, prevState) => {
|
||||
if (!_.isEqual(state.revealables, prevState.revealables)) {
|
||||
this.revealables = state.revealables;
|
||||
this.revealableCoords = generateRevealableCoords();
|
||||
this.revealableObjects = this.revealables.map(
|
||||
(revealable, i) =>
|
||||
new Revealable(revealable, {
|
||||
x: this.revealableCoords[i].x,
|
||||
y: this.revealableCoords[i].y,
|
||||
w: this.revealables[i].size,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Check if everything was found, if so, get back to overview screen
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { combineLatest } from 'rxjs';
|
|||
import { mp5 } from '../../main';
|
||||
import { areasColliding, playerHead$, revealedArea$ } from '../area';
|
||||
import { colors } from '../constants/colors';
|
||||
import store from '../store';
|
||||
import { Area } from '../types';
|
||||
|
||||
export enum RevealableTypes {
|
||||
|
|
@ -24,22 +25,42 @@ enum RevealableStates {
|
|||
HIDDEN = 'HIDDEN',
|
||||
REVEALED = 'REVEALED',
|
||||
FOUND = 'FOUND',
|
||||
INACTIVE = 'INACTIVE',
|
||||
}
|
||||
|
||||
export class Revealable {
|
||||
state: RevealableStates = RevealableStates.HIDDEN;
|
||||
area: Area;
|
||||
|
||||
type: RevealableTypes;
|
||||
name: string;
|
||||
path: string;
|
||||
contents: string;
|
||||
url: string;
|
||||
imageUrl: string;
|
||||
|
||||
isHovered: boolean;
|
||||
isRevealed: boolean;
|
||||
wasInteractedWith: boolean;
|
||||
|
||||
minSize: number = 5;
|
||||
currentSize: number;
|
||||
maxSize: number;
|
||||
|
||||
pulseCurrentSize: number;
|
||||
pulseOpacity: number = 255;
|
||||
pulseCountUp: boolean;
|
||||
|
||||
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.currentSize = this.minSize;
|
||||
this.pulseCurrentSize = area.w;
|
||||
this.maxSize = area.w;
|
||||
|
||||
combineLatest([revealedArea$, playerHead$]).subscribe(([revealedArea, playerHead]) => {
|
||||
|
|
@ -54,15 +75,19 @@ export class Revealable {
|
|||
w: this.currentSize,
|
||||
});
|
||||
|
||||
if (
|
||||
((isRevealed && isHovered) || (!isRevealed && isHovered)) &&
|
||||
(this.state === RevealableStates.REVEALED || this.state === RevealableStates.FOUND)
|
||||
) {
|
||||
this.state = RevealableStates.FOUND;
|
||||
} else if (isRevealed && !isHovered) {
|
||||
this.state = RevealableStates.REVEALED;
|
||||
if (this.wasInteractedWith) {
|
||||
this.state = RevealableStates.INACTIVE;
|
||||
} else {
|
||||
this.state = RevealableStates.HIDDEN;
|
||||
if (
|
||||
((isRevealed && isHovered) || (!isRevealed && isHovered)) &&
|
||||
(this.state === RevealableStates.REVEALED || this.state === RevealableStates.FOUND)
|
||||
) {
|
||||
this.state = RevealableStates.FOUND;
|
||||
} else if (isRevealed && !isHovered) {
|
||||
this.state = RevealableStates.REVEALED;
|
||||
} else {
|
||||
this.state = RevealableStates.HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
this.isHovered = this.state === RevealableStates.FOUND ? isHovered : false;
|
||||
|
|
@ -79,14 +104,27 @@ export class Revealable {
|
|||
mp5.fill(mp5.color(colors.greyLight));
|
||||
mp5.ellipse(this.area.x, this.area.y, this.currentSize);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
public onClick() {
|
||||
if (this.isHovered) {
|
||||
if (this.isHovered && !this.wasInteractedWith) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,16 @@ const store = create<State>(
|
|||
infoMessageShown: false,
|
||||
infoMessages: [],
|
||||
addInfoMessage: (newMessage) =>
|
||||
set((state) => ({ infoMessages: [...state.infoMessages, newMessage] })),
|
||||
set((state) => ({ ...state, infoMessages: [...state.infoMessages, newMessage] })),
|
||||
userMessages: [],
|
||||
addUserMessage: (newMessage) =>
|
||||
set((state) => ({ userMessages: [...state.userMessages, newMessage] })),
|
||||
set((state) => ({ ...state, userMessages: [...state.userMessages, newMessage] })),
|
||||
revealables: [],
|
||||
setProjectMetadata: (projectName) =>
|
||||
set({
|
||||
set((state) => ({
|
||||
...state,
|
||||
revealables: getRevealablesforSubproject(projectName, project.subprojects),
|
||||
}),
|
||||
})),
|
||||
}))
|
||||
);
|
||||
|
||||
|
|
|
|||
Reference in a new issue