implement basic arkanoid version
This commit is contained in:
+181
@@ -0,0 +1,181 @@
|
||||
import { Position, Size, Velocity } from './types';
|
||||
import { between } from './utils';
|
||||
|
||||
export abstract class Element {
|
||||
instance: HTMLElement;
|
||||
elements: Element[] = [];
|
||||
style: CSSStyleDeclaration;
|
||||
isDestroyed = false;
|
||||
|
||||
protected constructor(public size: Size, public pos: Position, public vel: Velocity = Velocity.create()) {
|
||||
this.instance = document.createElement('div');
|
||||
this.style = this.instance.style;
|
||||
this.style.transition = 'transform linear 20ms';
|
||||
this.translate = this.translate.bind(this);
|
||||
this.bounce = this.bounce.bind(this);
|
||||
this.update = this.update.bind(this);
|
||||
this.reset = this.reset.bind(this);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.intersects = this.intersects.bind(this);
|
||||
}
|
||||
|
||||
destroy(): this {
|
||||
this.isDestroyed = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
get top(): number {
|
||||
return this.pos.y;
|
||||
}
|
||||
get right(): number {
|
||||
return this.pos.x + this.size.width;
|
||||
}
|
||||
get bottom(): number {
|
||||
return this.pos.y + this.size.height;
|
||||
}
|
||||
get left(): number {
|
||||
return this.pos.x;
|
||||
}
|
||||
|
||||
appendElement(element: Element): this {
|
||||
this.elements.push(element);
|
||||
this.instance.appendChild(element.instance);
|
||||
return this;
|
||||
}
|
||||
removeElement(element: Element): this {
|
||||
this.elements.splice(this.elements.indexOf(element), 1);
|
||||
this.instance.removeChild(element.instance);
|
||||
return this;
|
||||
}
|
||||
removeAllElements(): this {
|
||||
while (this.instance.childNodes.length) {
|
||||
this.instance.removeChild(this.instance.childNodes[0]);
|
||||
}
|
||||
this.elements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
move(pos: Position): this {
|
||||
this.pos = pos;
|
||||
return this;
|
||||
}
|
||||
|
||||
translate(): this {
|
||||
this.style.transform = `translate(${this.pos.x}px, ${this.pos.y}px)`;
|
||||
return this;
|
||||
}
|
||||
|
||||
isInBoundsX(x: number, w: number): boolean {
|
||||
return x >= 0 && x + w <= this.size.width;
|
||||
}
|
||||
|
||||
isInBoundsY(y: number, h: number): boolean {
|
||||
return y >= 0 && y + h <= this.size.height;
|
||||
}
|
||||
|
||||
isInBounds(pos: Position, size: Size): boolean {
|
||||
return this.isInBoundsX(pos.x, size.width) && this.isInBoundsY(pos.y, size.height);
|
||||
}
|
||||
|
||||
intersectsTop(element: Element): boolean {
|
||||
let yIntersects = false;
|
||||
let xIntersects = false;
|
||||
|
||||
if (between(element.bottom, this.top, this.top + Math.round(this.size.height / 2))) {
|
||||
yIntersects = true;
|
||||
}
|
||||
|
||||
if (between(element.left, this.left, this.right) || between(element.right, this.left, this.right)) {
|
||||
xIntersects = true;
|
||||
}
|
||||
|
||||
return yIntersects && xIntersects;
|
||||
}
|
||||
|
||||
intersectsBottom(element: Element): boolean {
|
||||
let yIntersects = false;
|
||||
let xIntersects = false;
|
||||
|
||||
if (between(element.top, this.bottom, this.bottom - Math.round(this.size.height / 2))) {
|
||||
yIntersects = true;
|
||||
}
|
||||
|
||||
if (between(element.left, this.left, this.right) || between(element.right, this.left, this.right)) {
|
||||
xIntersects = true;
|
||||
}
|
||||
|
||||
return yIntersects && xIntersects;
|
||||
}
|
||||
|
||||
intersectsLeft(element: Element): boolean {
|
||||
let yIntersects = false;
|
||||
let xIntersects = false;
|
||||
|
||||
if (between(element.right, this.left, this.left + Math.round(this.size.width / 2))) {
|
||||
xIntersects = true;
|
||||
}
|
||||
|
||||
if (between(element.top, this.top, this.bottom) || between(element.bottom, this.top, this.bottom)) {
|
||||
yIntersects = true;
|
||||
}
|
||||
|
||||
return yIntersects && xIntersects;
|
||||
}
|
||||
|
||||
intersectsRight(element: Element): boolean {
|
||||
let yIntersects = false;
|
||||
let xIntersects = false;
|
||||
|
||||
if (between(element.left, this.right - Math.round(this.size.width / 2), this.right)) {
|
||||
xIntersects = true;
|
||||
}
|
||||
|
||||
if (between(element.top, this.top, this.bottom) || between(element.bottom, this.top, this.bottom)) {
|
||||
yIntersects = true;
|
||||
}
|
||||
|
||||
return yIntersects && xIntersects;
|
||||
}
|
||||
|
||||
intersects(element: Element): boolean {
|
||||
return (
|
||||
this.intersectsTop(element) ||
|
||||
this.intersectsRight(element) ||
|
||||
this.intersectsLeft(element) ||
|
||||
this.intersectsBottom(element)
|
||||
);
|
||||
}
|
||||
|
||||
bounce(element: Element): boolean {
|
||||
if (this.intersectsTop(element)) {
|
||||
element.vel.y = Math.abs(element.vel.y) * -1;
|
||||
return true;
|
||||
} else if (this.intersectsBottom(element)) {
|
||||
element.vel.y = Math.abs(element.vel.y);
|
||||
return true;
|
||||
} else if (this.intersectsLeft(element)) {
|
||||
element.vel.x = Math.abs(element.vel.x) * -1;
|
||||
return true;
|
||||
} else if (this.intersectsRight(element)) {
|
||||
element.vel.x = Math.abs(element.vel.x);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
update(): this {
|
||||
this.elements.forEach(element => {
|
||||
if (element.isDestroyed) {
|
||||
this.removeElement(element);
|
||||
} else {
|
||||
element.update();
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
reset(): this {
|
||||
this.elements.forEach(element => element.reset());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user