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