mirror of
https://github.com/Sheldan/canvas.git
synced 2026-01-03 23:43:46 +00:00
survivors: restricting player to world bounds
reworking how repeated collisions are handled for projectiles for the purpose of piercing projectiles
This commit is contained in:
@@ -6,7 +6,7 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
private _position: Vector;
|
||||
private _stats: Stats;
|
||||
private _color: string;
|
||||
private _status: Status;
|
||||
private _status: PlayerStatus;
|
||||
private _weapons: [Weapon] = []
|
||||
|
||||
// temp
|
||||
@@ -27,7 +27,7 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
player._color = 'blue';
|
||||
player._stats = Stats.defaultPlayerStats();
|
||||
player._speed = new Vector(0, 0)
|
||||
player._status = new Status(10, 0);
|
||||
player._status = new PlayerStatus(10, 0);
|
||||
return player;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
return this._stats;
|
||||
}
|
||||
|
||||
get status(): Status {
|
||||
get status(): PlayerStatus {
|
||||
return this._status;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
}
|
||||
}
|
||||
|
||||
export class Status {
|
||||
export class PlayerStatus {
|
||||
constructor(private _health: number, private _wealth: number) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {Enemy} from "./Enemies.ts";
|
||||
import type {Player} from "./Player.ts";
|
||||
import {Player} from "./Player.ts";
|
||||
import {Projectile} from "./projectile.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
@@ -40,6 +39,15 @@ export class World {
|
||||
this._drops.push(drop)
|
||||
}
|
||||
|
||||
movePlayer(vector: Vector) {
|
||||
this._player.position.x += vector.x;
|
||||
this._player.position.y += vector.y;
|
||||
this._player.position.x = Math.min(this.size.x - this._player.getSize(), this._player.position.x)
|
||||
this._player.position.x = Math.max(this._player.getSize(), this._player.position.x)
|
||||
this._player.position.y = Math.min(this.size.y -this._player.getSize(), this._player.position.y)
|
||||
this._player.position.y = Math.max(this._player.getSize(), this._player.position.y)
|
||||
}
|
||||
|
||||
removeDrop(drop: Drop) {
|
||||
this._drops = this._drops.filter(item => item !== drop)
|
||||
}
|
||||
@@ -75,9 +83,16 @@ export class World {
|
||||
}
|
||||
|
||||
getClosestTargetTo(point: Vector): [number, Placeable | undefined] | undefined {
|
||||
return this.getClosestTargetToButNot(point, undefined)
|
||||
}
|
||||
|
||||
getClosestTargetToButNot(point: Vector, placeAble?: Placeable): [number, Placeable | undefined] | undefined {
|
||||
let currentTarget;
|
||||
let currentDistance = Number.MAX_SAFE_INTEGER;
|
||||
this._enemies.forEach(enemy => {
|
||||
if(placeAble && enemy === placeAble) {
|
||||
return;
|
||||
}
|
||||
let distance = point.distanceTo(enemy.getPosition());
|
||||
if(distance < currentDistance) {
|
||||
currentDistance = distance;
|
||||
|
||||
@@ -63,7 +63,7 @@ export class MoneyDrop extends BasicDrop {
|
||||
let drop = new MoneyDrop(world, position)
|
||||
drop.worth = 1;
|
||||
drop._size = 1;
|
||||
drop._color = 'yellow';
|
||||
drop._color = 'orange';
|
||||
world.addDrop(drop)
|
||||
return drop;
|
||||
}
|
||||
|
||||
@@ -65,16 +65,16 @@ function makeKey(char, fun) {
|
||||
|
||||
let keys = {};
|
||||
makeKey('w', function () {
|
||||
world.player.position.y += -world.player.stats.speed
|
||||
world.movePlayer(new Vector(0, -world.player.stats.speed))
|
||||
})
|
||||
makeKey('s', function () {
|
||||
world.player.position.y += world.player.stats.speed
|
||||
world.movePlayer(new Vector(0, world.player.stats.speed))
|
||||
})
|
||||
makeKey('a', function () {
|
||||
world.player.position.x += -world.player.stats.speed
|
||||
world.movePlayer(new Vector(-world.player.stats.speed, 0))
|
||||
})
|
||||
makeKey('d', function () {
|
||||
world.player.position.x += world.player.stats.speed
|
||||
world.movePlayer(new Vector(world.player.stats.speed, 0))
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,10 @@ export abstract class Projectile implements Acting, Placeable {
|
||||
protected world: World;
|
||||
protected parent: any;
|
||||
protected color: string
|
||||
private stats: ProjectileStats;
|
||||
private status: ProjectileStatus;
|
||||
protected stats: ProjectileStats;
|
||||
protected status: ProjectileStatus;
|
||||
protected lastPosition: Vector;
|
||||
protected lastColliding?: Placeable;
|
||||
|
||||
constructor(position: Vector, speedVec: Vector, stats: ProjectileStats, world: World, parent: any) {
|
||||
this.position = position.clone();
|
||||
@@ -26,20 +28,20 @@ export abstract class Projectile implements Acting, Placeable {
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
if(this.status.collisionCooldown.cooledDown()) {
|
||||
if(this.parent !== this.world.player) {
|
||||
if(this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.stats.size)) {
|
||||
this.impactPlayer()
|
||||
this.status.collisionCooldown.resetCooldown()
|
||||
}
|
||||
} else if(this.parent === this.world.player) {
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.position);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined && closestTargetTo[1]?.getPosition().distanceTo(this.position) < (this.stats.size + closestTargetTo[1]?.getSize())) {
|
||||
let target: Placeable = closestTargetTo[1]!;
|
||||
if(this.parent !== this.world.player) {
|
||||
if(this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.stats.size) && this.status.collisionCooldown.cooledDown()) {
|
||||
this.impactPlayer()
|
||||
this.status.collisionCooldown.resetCooldown()
|
||||
}
|
||||
} else if(this.parent === this.world.player) {
|
||||
let closestTargetTo = this.world.getClosestTargetToButNot(this.position, this.lastColliding);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined && closestTargetTo[1]?.getPosition().distanceTo(this.position) < (this.stats.size + closestTargetTo[1]?.getSize())) {
|
||||
let target: Placeable = closestTargetTo[1]!;
|
||||
if(target !== this.lastColliding) {
|
||||
if(InstanceOfUtils.instanceOfHealthy(target)) {
|
||||
let healthy = target as Healthy;
|
||||
healthy.takeDamage(this.stats.damage)
|
||||
if(this.status.piercingsLeft <= 0) {
|
||||
if(!this.status.hasPiercingLeft()) {
|
||||
this.world.removeProjectile(this)
|
||||
}
|
||||
this.status.decreasePiercings()
|
||||
@@ -47,9 +49,12 @@ export abstract class Projectile implements Acting, Placeable {
|
||||
this.world.removeProjectile(this)
|
||||
}
|
||||
}
|
||||
this.lastColliding = target;
|
||||
} else {
|
||||
this.lastColliding = undefined;
|
||||
}
|
||||
}
|
||||
this.status.collisionCooldown.decreaseCooldown();
|
||||
this.status.collisionCooldown.decreaseCooldown()
|
||||
this.checkWorldBorder()
|
||||
}
|
||||
|
||||
@@ -61,7 +66,9 @@ export abstract class Projectile implements Acting, Placeable {
|
||||
|
||||
impactPlayer() {
|
||||
this.world.player.takeDamage(this.stats.damage)
|
||||
this.world.removeProjectile(this)
|
||||
if(!this.status.hasPiercingLeft()) {
|
||||
this.world.removeProjectile(this)
|
||||
}
|
||||
};
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
@@ -69,6 +76,7 @@ export abstract class Projectile implements Acting, Placeable {
|
||||
}
|
||||
|
||||
move() {
|
||||
this.lastPosition = this.position.clone()
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
@@ -89,6 +97,7 @@ export class StraightProjectile extends Projectile {
|
||||
}
|
||||
|
||||
move() {
|
||||
super.move()
|
||||
this.position = straightMove(this.position, this.speedVec)
|
||||
}
|
||||
|
||||
@@ -111,35 +120,35 @@ export class HomingProjectile extends Projectile {
|
||||
}
|
||||
|
||||
move() {
|
||||
super.move()
|
||||
this.position = moveInDirectionOf(this.position, this.target.getPosition(), this.speedVec.vecLength())
|
||||
if(InstanceOfUtils.instanceOfHealthy(this.target)) {
|
||||
let target = this.target as Healthy
|
||||
if(target.dead()) {
|
||||
if(this.position.distanceTo(this.target.getPosition()) < (this.target.getSize() + this.getSize())) {
|
||||
this.world.removeProjectile(this)
|
||||
return;
|
||||
}
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position)
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.position)
|
||||
|
||||
let dir = Vector.createVector(this.target.getPosition(), this.position).normalize()
|
||||
let oldDir = Vector.createVector(this.position, this.lastPosition).normalize()
|
||||
if (closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let dir = Vector.createVector(this.target.getPosition(), this.position).normalize()
|
||||
let newTargetPosition = closestTargetTo[1]!.getPosition();
|
||||
let newDir = Vector.createVector(newTargetPosition, this.position).normalize()
|
||||
let newDirAngle = newDir.angleTo(dir);
|
||||
if(Math.abs(newDirAngle) < toRad(60)) {
|
||||
if(Math.abs(newDirAngle) >= toRad(150)) {
|
||||
this.target = closestTargetTo[1]!;
|
||||
} else {
|
||||
this.target = new Point(this.target.getPosition().add(dir.normalize().multiply(Math.max(this.world.size.x, this.world.size.y))))
|
||||
this.target = new Point(this.position.add(oldDir.multiply(Math.max(this.world.size.x, this.world.size.y))))
|
||||
}
|
||||
} else {
|
||||
this.target = new Point(this.position.add(oldDir.multiply(Math.max(this.world.size.x, this.world.size.y))))
|
||||
}
|
||||
}
|
||||
}
|
||||
this.position = moveInDirectionOf(this.position, this.target.getPosition(), this.speedVec.vecLength())
|
||||
this.checkWorldBorder()
|
||||
}
|
||||
|
||||
static createHomingProjectile(world: World, start: Vector, parent: any, target: Placeable, stats: ProjectileStats, color?: string) {
|
||||
|
||||
let projectile = new HomingProjectile(start, new Vector(5, 1), stats, world, parent, target)
|
||||
let projectile = new HomingProjectile(start, new Vector(0, stats.speed), stats, world, parent, target)
|
||||
projectile.color = color === undefined ? 'red' : color!;
|
||||
world.addProjectile(projectile)
|
||||
return projectile;
|
||||
@@ -160,6 +169,10 @@ export class ProjectileStatus {
|
||||
return this._piercingsLeft;
|
||||
}
|
||||
|
||||
hasPiercingLeft(): boolean {
|
||||
return this.piercingsLeft >= 0;
|
||||
}
|
||||
|
||||
|
||||
get collisionCooldown(): Cooldown {
|
||||
return this._collisionCooldown;
|
||||
@@ -175,11 +188,13 @@ export class ProjectileStats {
|
||||
private _piercings: number;
|
||||
private _size: number;
|
||||
private _damage: number;
|
||||
private _speed: number;
|
||||
|
||||
constructor(piercings: number, size: number, damage: number) {
|
||||
constructor(piercings: number, size: number, damage: number, _speed: number) {
|
||||
this._piercings = piercings;
|
||||
this._size = size;
|
||||
this._damage = damage
|
||||
this._speed = _speed;
|
||||
}
|
||||
|
||||
get piercings(): number {
|
||||
@@ -191,6 +206,10 @@ export class ProjectileStats {
|
||||
}
|
||||
|
||||
|
||||
get speed(): number {
|
||||
return this._speed;
|
||||
}
|
||||
|
||||
get damage(): number {
|
||||
return this._damage;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import {Vector} from "./base.ts";
|
||||
|
||||
export class Pistol implements Weapon {
|
||||
|
||||
private player: Player
|
||||
private readonly player: Player
|
||||
private shootInterval: number;
|
||||
private shootCooldown: number = 0;
|
||||
private world: World;
|
||||
private readonly world: World;
|
||||
private offset: Vector;
|
||||
private projectiles: [Projectile] = []
|
||||
private color: string;
|
||||
@@ -37,7 +37,7 @@ export class Pistol implements Weapon {
|
||||
private createProjectile(): boolean {
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let stats = new ProjectileStats(0, 1, 5)
|
||||
let stats = new ProjectileStats(2, 1, 5, 1)
|
||||
let projectile = HomingProjectile.createHomingProjectile(this.world, this.getPosition(), this.player, closestTargetTo[1]!, stats, 'yellow')
|
||||
this.projectiles.push(projectile)
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user