Somewhat working ConveyorBin

This commit is contained in:
Kaloian Venkov 2021-03-13 15:56:30 +02:00
parent d1e9ccdf8b
commit d0c539306d
34 changed files with 281 additions and 34 deletions

View File

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

View File

@ -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>

View File

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

View File

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

View File

@ -4,9 +4,8 @@ export const mock_minigames: Saved<Minigame>[] = [
{
id: '0',
el: {
name: 'Рециклиране',
name: 'ConveyorBin',
url: '/minigames/conveyor-belt',
comingSoon: true,
}
},
{

View File

@ -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: {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB