Somewhat working ConveyorBin
@ -1,6 +1,8 @@
|
||||
import { Component, ElementRef, NgZone, OnInit, ViewChild, ViewChildren } from '@angular/core';
|
||||
import { NavigationEnd, NavigationStart, Router, RouterEvent } from '@angular/router';
|
||||
import { IgxRadioComponent, IgxRadioGroupDirective } from 'igniteui-angular';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { filter, map, tap } from 'rxjs/operators';
|
||||
import { Answer, Card, DbService, Question, Saved } from '../db.service';
|
||||
import { Medal, UserdataService } from '../userdata.service';
|
||||
|
||||
@ -39,9 +41,18 @@ export class MinigameBiotriviaComponent implements OnInit {
|
||||
constructor(
|
||||
private db: DbService,
|
||||
private userdata: UserdataService,
|
||||
private router: Router,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.router.events.pipe(
|
||||
filter((e: any) => e instanceof NavigationStart),
|
||||
// tslint:disable-next-line: deprecation
|
||||
).subscribe((e: NavigationStart) => {
|
||||
console.log(e);
|
||||
this.player.pause();
|
||||
this.player.remove();
|
||||
});
|
||||
}
|
||||
|
||||
endGame(): void {
|
||||
@ -64,7 +75,7 @@ export class MinigameBiotriviaComponent implements OnInit {
|
||||
this.wonCard = this.db.getCard(newCard);
|
||||
}
|
||||
|
||||
const id = this.db.getAllMinigames().filter(v => v.el.name === 'BioTrivia')[0].id;
|
||||
const id = '1';
|
||||
const data = this.userdata.getMinigameUserdata(id);
|
||||
|
||||
let medal = Medal.None;
|
||||
@ -83,7 +94,7 @@ export class MinigameBiotriviaComponent implements OnInit {
|
||||
this.animateElements(
|
||||
this.ongoingElementRef.first.nativeElement,
|
||||
this.endingElementRef.first.nativeElement
|
||||
// tslint:disable-next-line: deprecation
|
||||
// tslint:disable-next-line: deprecation
|
||||
).subscribe(() => {
|
||||
this.stage = 'ended';
|
||||
});
|
||||
@ -240,6 +251,11 @@ export class MinigameBiotriviaComponent implements OnInit {
|
||||
// tslint:disable-next-line: deprecation
|
||||
this.animateElements(endingEl, ongoingEl).subscribe(() => {
|
||||
this.stage = 'ongoing';
|
||||
this.player = document.createElement('audio');
|
||||
|
||||
this.player.src = '/assets/sound/music/biotrivia.wav';
|
||||
this.player.loop = true;
|
||||
this.player.play();
|
||||
});
|
||||
}, 20);
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
<div class="container">
|
||||
<div class="conveyor" #conveyor>
|
||||
<img src="/assets/images/conveyor-belt/conveyor-{{conveyorFrame + 1}}.png" class="image">
|
||||
<img src="/assets/images/conveyor-belt/conveyor-end-{{conveyorFrame + 1}}.png" class="image">
|
||||
</div>
|
||||
<div class="bins" [style.left]="(146 - 50) + 'px'" #bins>
|
||||
<img src="/assets/images/conveyor-belt/bin-plastic.png" class="image" #bin>
|
||||
<img src="/assets/images/conveyor-belt/bin-other.png" class="image" #bin>
|
||||
<img src="/assets/images/conveyor-belt/bin-paper.png" class="image" #bin>
|
||||
<img src="/assets/images/conveyor-belt/bin-glass.png" class="image" #bin>
|
||||
</div>
|
||||
</div>
|
@ -1,4 +1,22 @@
|
||||
.canvas {
|
||||
img {
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
.conveyor {
|
||||
position: absolute;
|
||||
top: 30vh;
|
||||
}
|
||||
.bins {
|
||||
position: absolute;
|
||||
bottom: 10vh;
|
||||
.image {
|
||||
max-height: unset;
|
||||
}
|
||||
transition: left 100ms;
|
||||
}
|
||||
|
||||
:host {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
@ -1,18 +1,237 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, NgZone, OnInit, ViewChild, ViewChildren } from '@angular/core';
|
||||
import { NavigationStart, Router } from '@angular/router';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { Saved } from '../db.service';
|
||||
|
||||
class Rect {
|
||||
public top: number;
|
||||
public left: number;
|
||||
public bottom: number;
|
||||
public right: number;
|
||||
|
||||
private checkPointInRect(x: number, y: number, rect: Rect): boolean {
|
||||
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
||||
}
|
||||
private checkRectInRect(a: Rect, b: Rect): boolean {
|
||||
return this.checkPointInRect(a.left, a.top, b) ||
|
||||
this.checkPointInRect(a.right, a.top, b) ||
|
||||
this.checkPointInRect(a.left, a.bottom, b) ||
|
||||
this.checkPointInRect(a.right, a.bottom, b);
|
||||
}
|
||||
|
||||
public collidesWith(rect: Rect): boolean {
|
||||
return this.checkRectInRect(this, rect) || this.checkRectInRect(rect, this);
|
||||
}
|
||||
|
||||
constructor(domRect: DOMRect | number, left?: number, right?: number, bottom?: number) {
|
||||
if (typeof domRect === 'number') {
|
||||
this.top = domRect;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
else {
|
||||
this.top = domRect.top;
|
||||
this.left = domRect.left;
|
||||
this.right = domRect.right;
|
||||
this.bottom = domRect.bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Conveyor {
|
||||
public element: HTMLElement;
|
||||
|
||||
public speed: number;
|
||||
|
||||
|
||||
public checkCollision(el: HTMLElement): boolean {
|
||||
const a = new Rect(this.element.getBoundingClientRect());
|
||||
const b = new Rect(el.getBoundingClientRect());
|
||||
|
||||
return a.collidesWith(b);
|
||||
}
|
||||
public getUpVelocity(el: HTMLElement): number {
|
||||
return this.element.getBoundingClientRect().top - el.getBoundingClientRect().bottom;
|
||||
}
|
||||
}
|
||||
class Bin {
|
||||
public acceptedTypes: string[];
|
||||
public element: HTMLElement;
|
||||
public checkTrashColission(trash: Trash): boolean {
|
||||
return new Rect(trash.element.getBoundingClientRect()).collidesWith(new Rect(this.element.getBoundingClientRect()));
|
||||
}
|
||||
public correctTrash(trash: Trash): boolean {
|
||||
return this.acceptedTypes.includes(trash.type);
|
||||
}
|
||||
}
|
||||
|
||||
class Trash {
|
||||
public imageUrl: string;
|
||||
public type: string;
|
||||
public velX: number;
|
||||
public velY: number;
|
||||
|
||||
public element: HTMLElement;
|
||||
|
||||
public thrownOut = new EventEmitter<boolean>();
|
||||
public dropped = new EventEmitter();
|
||||
|
||||
public update(gravity: number, friction: number, conveyor: Conveyor, ...bins: Bin[]): { x: number, y: number, bin?: Bin } {
|
||||
let x;
|
||||
let y;
|
||||
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
x = rect.left;
|
||||
y = rect.top;
|
||||
|
||||
this.velY += gravity;
|
||||
y += this.velY;
|
||||
|
||||
if (conveyor.checkCollision(this.element)) {
|
||||
const velCorrection = conveyor.getUpVelocity(this.element);
|
||||
this.velY = 0;
|
||||
y += velCorrection;
|
||||
this.velX = conveyor.speed;
|
||||
}
|
||||
else if (Math.abs(this.velX) > 0) {
|
||||
this.velX = Math.sign(this.velX) * (Math.abs(this.velX) - friction);
|
||||
}
|
||||
|
||||
const bin = bins.find(v => new Rect(rect).collidesWith(new Rect(v.element.getBoundingClientRect())));
|
||||
x += this.velX;
|
||||
|
||||
this.element.style.left = x + 'px';
|
||||
this.element.style.top = y + 'px';
|
||||
|
||||
return {x, y, bin};
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-minigame-conveyor-recycling',
|
||||
templateUrl: './minigame-conveyor-recycling.component.html',
|
||||
styleUrls: ['./minigame-conveyor-recycling.component.scss']
|
||||
selector: 'app-minigame-conveyor-recycling',
|
||||
templateUrl: './minigame-conveyor-recycling.component.html',
|
||||
styleUrls: ['./minigame-conveyor-recycling.component.scss']
|
||||
})
|
||||
export class MinigameConveyorRecyclingComponent implements OnInit {
|
||||
export class MinigameConveyorRecyclingComponent implements AfterViewInit {
|
||||
conveyorFrame = 1;
|
||||
frameCounterID: number;
|
||||
trashTrowerID: number;
|
||||
trashSpeed = 1000;
|
||||
trashTypes: string[] = [ 'plastic', 'metal', 'glass', 'paper', 'other' ];
|
||||
nextId = 0;
|
||||
|
||||
constructor() { }
|
||||
@ViewChildren('conveyor') conveyorElement;
|
||||
@ViewChildren('bin') binElements;
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
bins: Bin[];
|
||||
|
||||
start() {
|
||||
conveyor: Conveyor;
|
||||
|
||||
}
|
||||
trashes: Saved<Trash>[] = [];
|
||||
|
||||
binWidth = 146;
|
||||
|
||||
milliseconds = 0;
|
||||
|
||||
keydownListener = (e) => {
|
||||
const code = e.keyCode as number;
|
||||
if (code === 65) console.log('move left');
|
||||
if (code === 68) console.log('move right');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private router: Router,
|
||||
private element: ElementRef,
|
||||
) { }
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.router.events.pipe(
|
||||
filter((e: any) => e instanceof NavigationStart),
|
||||
// tslint:disable-next-line: deprecation
|
||||
).subscribe((e: NavigationStart) => {
|
||||
this.end();
|
||||
});
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
end(): void {
|
||||
clearInterval(this.frameCounterID);
|
||||
document.body.removeEventListener('keydown', this.keydownListener);
|
||||
}
|
||||
|
||||
start(): void {
|
||||
document.body.addEventListener('keydown', this.keydownListener);
|
||||
|
||||
this.bins = this.binElements._results.map((v: ElementRef) => {
|
||||
const el = v.nativeElement;
|
||||
const bin = new Bin();
|
||||
bin.element = el;
|
||||
bin.acceptedTypes = ['paper'];
|
||||
|
||||
return bin;
|
||||
});
|
||||
|
||||
this.conveyor = new Conveyor();
|
||||
this.conveyor.element = this.conveyorElement.first.nativeElement;
|
||||
this.conveyor.speed = 2;
|
||||
this.frameCounterID = setInterval(() => {
|
||||
this.zone.run(() => {
|
||||
this.conveyorFrame = (++this.conveyorFrame % 3);
|
||||
});
|
||||
}, 1000) as any as number;
|
||||
this.frameCounterID = setInterval(() => {
|
||||
if (this.milliseconds % (1000 / 10) === 0) {
|
||||
const trash = new Trash();
|
||||
const element = document.createElement('img');
|
||||
element.style.position = 'absolute';
|
||||
|
||||
trash.dropped.subscribe(() => {
|
||||
trash.element.remove();
|
||||
|
||||
});
|
||||
|
||||
trash.velX = 2;
|
||||
trash.velY = 0;
|
||||
|
||||
trash.type = this.getRandomType();
|
||||
trash.imageUrl = `/assets/images/conveyor-belt/${trash.type}-${Math.floor(Math.random() * 3) + 1}.png`;
|
||||
|
||||
element.src = trash.imageUrl;
|
||||
trash.element = element;
|
||||
|
||||
this.element.nativeElement.prepend(element);
|
||||
|
||||
this.trashes.push({ id: (this.nextId++).toString(), el: trash });
|
||||
}
|
||||
|
||||
this.trashes.forEach((trash, i) => {
|
||||
const newPos = trash.el.update(9 / 100, .05, this.conveyor, ...this.bins);
|
||||
if (newPos.y > document.body.getBoundingClientRect().bottom) {
|
||||
trash.el.element.remove();
|
||||
this.trashes.splice(i, 1);
|
||||
}
|
||||
|
||||
if (newPos.bin) {
|
||||
trash.el.element.remove();
|
||||
this.trashes.splice(i, 1);
|
||||
}
|
||||
});
|
||||
|
||||
this.milliseconds++;
|
||||
}, 10) as any as number;
|
||||
|
||||
|
||||
}
|
||||
|
||||
getRandomType(): string {
|
||||
const i = Math.floor(Math.random() * this.trashTypes.length);
|
||||
return this.trashTypes[i];
|
||||
}
|
||||
getRandomTrash(): string {
|
||||
const i1 = Math.floor(Math.random() * 3);
|
||||
return this.getRandomType() + '-' + i1 + '.png';
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@ export const mock_minigames: Saved<Minigame>[] = [
|
||||
{
|
||||
id: '0',
|
||||
el: {
|
||||
name: 'Рециклиране',
|
||||
name: 'ConveyorBin',
|
||||
url: '/minigames/conveyor-belt',
|
||||
comingSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2,7 +2,7 @@ import { Question, Saved } from "./db.service";
|
||||
|
||||
export const mock_questions: Saved<Question>[] = [
|
||||
{
|
||||
id: '0',
|
||||
id: '1',
|
||||
el: {
|
||||
category: 'animals',
|
||||
photoUrlsAbove: [ '/assets/images/questions/slon.jpg' ],
|
||||
@ -18,23 +18,6 @@ export const mock_questions: Saved<Question>[] = [
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
el: {
|
||||
category: 'animals',
|
||||
photoUrlsAbove: [ '/assets/images/questions/carski orel.jpg' ],
|
||||
question: 'Каква е главната причина за намаляването на бройките Царски орли?',
|
||||
answer: {
|
||||
choises: [
|
||||
'Бракониери',
|
||||
'Замърсяване',
|
||||
'Отсичане на горите',
|
||||
'Електрически стълбове'
|
||||
],
|
||||
correctChoise: 'Електрически стълбове',
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
el: {
|
||||
|
BIN
apollo-frontend/src/assets/images/conveyor-belt/bin-glass.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/bin-other.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/bin-paper.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/bin-plastic.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/conveyor-1.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/conveyor-2.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/conveyor-3.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 821 B |
After Width: | Height: | Size: 860 B |
After Width: | Height: | Size: 837 B |
BIN
apollo-frontend/src/assets/images/conveyor-belt/glass-1.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/glass-2.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/glass-3.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/metal-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/metal-2.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/metal-3.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/other-1.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/other-2.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/other-3.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/paper-1.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/paper-2.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/paper-3.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/plastic-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/plastic-2.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
apollo-frontend/src/assets/images/conveyor-belt/plastic-3.png
Normal file
After Width: | Height: | Size: 1.3 KiB |