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

View file

@ -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
});
}

View file

@ -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);
}
}

View file

@ -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),
}),
})),
}))
);