mirror of
https://github.com/Sheldan/canvas.git
synced 2026-04-16 04:21:46 +00:00
survivors: adding collision for faster projectiles to also consider collisions between ticks
differentiating between pistol and homing pistol using projectile speed for straight projectile
This commit is contained in:
@@ -22,8 +22,11 @@ export class Player implements Drawable, Acting, Healthy {
|
|||||||
this._weapons.forEach(weapon => weapon.draw(ctx))
|
this._weapons.forEach(weapon => weapon.draw(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static generatePlayer(): Player {
|
public static generatePlayer(position?: Vector): Player {
|
||||||
let player = new Player(new Vector(500, 500));
|
if(position === undefined) {
|
||||||
|
position = new Vector(500, 500)
|
||||||
|
}
|
||||||
|
let player = new Player(position);
|
||||||
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)
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ export class Vector {
|
|||||||
return new Vector(tip.x - shaft.x, tip.y - shaft.y);
|
return new Vector(tip.x - shaft.x, tip.y - shaft.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zero() {
|
||||||
|
return new Vector(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
normalize(): Vector {
|
normalize(): Vector {
|
||||||
let length = this.vecLength();
|
let length = this.vecLength();
|
||||||
return new Vector(this.x / length, this.y / length)
|
return new Vector(this.x / length, this.y / length)
|
||||||
@@ -47,7 +51,7 @@ export class Vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dotProduct(vector: Vector): number {
|
dotProduct(vector: Vector): number {
|
||||||
return this._x * vector._x + this._y * vector._y;
|
return (this._x * vector._x + this._y * vector._y) / Math.pow(vector.vecLength(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
angleTo(vector: Vector): number {
|
angleTo(vector: Vector): number {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {Player} from "./Player.ts";
|
|||||||
import {Vector} from "./base.ts";
|
import {Vector} from "./base.ts";
|
||||||
import {BasicEnemy, Enemy, HealthEnemy, ShootingEnemy} from "./Enemies.ts";
|
import {BasicEnemy, Enemy, HealthEnemy, ShootingEnemy} from "./Enemies.ts";
|
||||||
import {HUD} from "./ui.ts";
|
import {HUD} from "./ui.ts";
|
||||||
import {Pistol} from "./weapons.ts";
|
import {HomingPistol, Pistol} from "./weapons.ts";
|
||||||
|
|
||||||
|
|
||||||
let hud: HUD;
|
let hud: HUD;
|
||||||
@@ -118,7 +118,7 @@ docReady(function () {
|
|||||||
}, 15_000)
|
}, 15_000)
|
||||||
|
|
||||||
player.addWeapon(Pistol.spawnPistol(world))
|
player.addWeapon(Pistol.spawnPistol(world))
|
||||||
player.addWeapon(Pistol.spawnPistol(world))
|
player.addWeapon(HomingPistol.spawnPistol(world))
|
||||||
hud = new HUD(world);
|
hud = new HUD(world);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type {Acting, Placeable, Healthy} from "./interfaces.ts";
|
|||||||
import type {Vector} from "./base.ts";
|
import type {Vector} from "./base.ts";
|
||||||
import {World} from "./World.ts";
|
import {World} from "./World.ts";
|
||||||
import {Cooldown, Point, Vector} from "./base.ts";
|
import {Cooldown, Point, Vector} from "./base.ts";
|
||||||
import {drawDot, moveInDirectionOf, straightMove, toRad} from "./utils.ts";
|
import {circleLineCollision, drawDot, moveInDirectionOf, straightMove, toRad} from "./utils.ts";
|
||||||
import {InstanceOfUtils} from "./instance.ts";
|
import {InstanceOfUtils} from "./instance.ts";
|
||||||
|
|
||||||
export abstract class Projectile implements Acting, Placeable {
|
export abstract class Projectile implements Acting, Placeable {
|
||||||
@@ -35,8 +35,10 @@ export abstract class Projectile implements Acting, Placeable {
|
|||||||
}
|
}
|
||||||
} 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.getClosestTargetToButNot(this.position, this.lastColliding);
|
||||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined && closestTargetTo[1]?.getPosition().distanceTo(this.position) < (this.stats.size + closestTargetTo[1]?.getSize())) {
|
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||||
let target: Placeable = closestTargetTo[1]!;
|
let target: Placeable = closestTargetTo[1]!;
|
||||||
|
if(target.getPosition().distanceTo(this.position) < (this.stats.size + target.getSize())
|
||||||
|
|| circleLineCollision(target.getPosition(), target.getSize(), this.position, this.lastPosition)) {
|
||||||
if(target !== this.lastColliding) {
|
if(target !== this.lastColliding) {
|
||||||
if(InstanceOfUtils.instanceOfHealthy(target)) {
|
if(InstanceOfUtils.instanceOfHealthy(target)) {
|
||||||
let healthy = target as Healthy;
|
let healthy = target as Healthy;
|
||||||
@@ -49,6 +51,7 @@ export abstract class Projectile implements Acting, Placeable {
|
|||||||
this.world.removeProjectile(this)
|
this.world.removeProjectile(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.lastColliding = target;
|
this.lastColliding = target;
|
||||||
} else {
|
} else {
|
||||||
this.lastColliding = undefined;
|
this.lastColliding = undefined;
|
||||||
@@ -102,7 +105,7 @@ export class StraightProjectile extends Projectile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static createStraightProjectile(world: World, start: Vector, targetPosition: Vector, parent: any, stats: ProjectileStats, color?: string) {
|
static createStraightProjectile(world: World, start: Vector, targetPosition: Vector, parent: any, stats: ProjectileStats, color?: string) {
|
||||||
let dirVector = Vector.createVector(targetPosition, start).normalize().multiply(2);
|
let dirVector = Vector.createVector(targetPosition, start).normalize().multiply(stats.speed);
|
||||||
let projectile = new StraightProjectile(start, dirVector, stats, world, parent)
|
let projectile = new StraightProjectile(start, dirVector, stats, world, parent)
|
||||||
projectile.color = color === undefined ? 'red' : color!;
|
projectile.color = color === undefined ? 'red' : color!;
|
||||||
world.addProjectile(projectile)
|
world.addProjectile(projectile)
|
||||||
@@ -127,11 +130,11 @@ export class HomingProjectile extends Projectile {
|
|||||||
if(target.dead()) {
|
if(target.dead()) {
|
||||||
let closestTargetTo = this.world.getClosestTargetTo(this.position)
|
let closestTargetTo = this.world.getClosestTargetTo(this.position)
|
||||||
|
|
||||||
let dir = Vector.createVector(this.target.getPosition(), this.position).normalize()
|
let dir = Vector.createVector(this.target.getPosition(), this.position)
|
||||||
let oldDir = Vector.createVector(this.position, this.lastPosition).normalize()
|
let oldDir = Vector.createVector(this.position, this.lastPosition).normalize()
|
||||||
if (closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
if (closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||||
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)
|
||||||
let newDirAngle = newDir.angleTo(dir);
|
let newDirAngle = newDir.angleTo(dir);
|
||||||
if(Math.abs(newDirAngle) >= toRad(150)) {
|
if(Math.abs(newDirAngle) >= toRad(150)) {
|
||||||
this.target = closestTargetTo[1]!;
|
this.target = closestTargetTo[1]!;
|
||||||
|
|||||||
@@ -24,3 +24,36 @@ export function toRad(angle) {
|
|||||||
export function toDegrees(angle) {
|
export function toDegrees(angle) {
|
||||||
return angle * 180 / Math.PI
|
return angle * 180 / Math.PI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function pointInsideCircle(circleCenter: Vector, radius: number, point: Vector) {
|
||||||
|
return circleCenter.distanceTo(point) < radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function linePointCollision(point: Vector, lineStart: Vector, lineEnd: Vector) {
|
||||||
|
let lineLength = Vector.createVector(lineEnd, lineStart).vecLength();
|
||||||
|
let distanceStart = Vector.createVector(lineStart, point).vecLength()
|
||||||
|
let distanceEnd = Vector.createVector(lineEnd, point).vecLength();
|
||||||
|
let buffer = 0.001
|
||||||
|
if((distanceStart + distanceEnd) >= (lineLength - buffer) && (distanceEnd + distanceStart) <= (lineLength + buffer)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function circleLineCollision(circleCenter: Vector, radius: number, lineStart: Vector, lineEnd: Vector) {
|
||||||
|
if(pointInsideCircle(circleCenter, radius, lineStart) || pointInsideCircle(circleCenter, radius, lineEnd)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let lineVector = Vector.createVector(lineEnd, lineStart)
|
||||||
|
let vectorCenterLine = Vector.createVector(circleCenter, lineStart)
|
||||||
|
let dot = vectorCenterLine.dotProduct(lineVector)
|
||||||
|
let closestX = lineStart.x + (dot * (lineVector.x))
|
||||||
|
let closestY = lineStart.y + (dot * (lineVector.y))
|
||||||
|
let closestPoint = new Vector(closestX, closestY);
|
||||||
|
let onSegment = linePointCollision(closestPoint, lineStart, lineEnd)
|
||||||
|
if(!onSegment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointInsideCircle(circleCenter, radius, closestPoint);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import type {Weapon} from "./interfaces.ts";
|
import type {Weapon} from "./interfaces.ts";
|
||||||
import {drawDot} from "./utils.ts";
|
import {drawDot} from "./utils.ts";
|
||||||
import {Player} from "./Player.ts";
|
import {Player} from "./Player.ts";
|
||||||
import {HomingProjectile, Projectile, ProjectileStats} from "./projectile.ts";
|
import {HomingProjectile, Projectile, ProjectileStats, StraightProjectile} from "./projectile.ts";
|
||||||
import {World} from "./World.ts";
|
import {World} from "./World.ts";
|
||||||
import {Vector} from "./base.ts";
|
import {Vector} from "./base.ts";
|
||||||
|
|
||||||
@@ -43,7 +43,52 @@ export abstract class BasicWeapon implements Weapon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Pistol extends BasicWeapon{
|
export class HomingPistol extends BasicWeapon {
|
||||||
|
|
||||||
|
private shootInterval: number;
|
||||||
|
private shootCooldown: number = 0;
|
||||||
|
|
||||||
|
private projectiles: [Projectile] = []
|
||||||
|
|
||||||
|
draw(ctx: CanvasRenderingContext2D) {
|
||||||
|
drawDot(this.getPosition(), 1, this.color, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
act() {
|
||||||
|
if(this.shootCooldown <= 0) {
|
||||||
|
if(this.createProjectile()) {
|
||||||
|
this.shootCooldown = this.shootInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.shootCooldown -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createProjectile(): boolean {
|
||||||
|
let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position);
|
||||||
|
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||||
|
let stats = new ProjectileStats(5, 1, 5, 5)
|
||||||
|
let projectile = HomingProjectile.createHomingProjectile(this.world, this.getPosition(), this.player, closestTargetTo[1]!, stats, 'yellow')
|
||||||
|
this.projectiles.push(projectile)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static spawnPistol(world: World, offset?: Vector) {
|
||||||
|
if(!offset) {
|
||||||
|
offset = new Vector(5, 5)
|
||||||
|
}
|
||||||
|
let pistol = new HomingPistol(world)
|
||||||
|
pistol.offset = offset;
|
||||||
|
pistol.size = 5;
|
||||||
|
pistol.color = 'yellow';
|
||||||
|
pistol.shootInterval = 50;
|
||||||
|
return pistol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Pistol extends BasicWeapon {
|
||||||
|
|
||||||
private shootInterval: number;
|
private shootInterval: number;
|
||||||
private shootCooldown: number = 0;
|
private shootCooldown: number = 0;
|
||||||
@@ -67,7 +112,7 @@ export class Pistol extends BasicWeapon{
|
|||||||
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(2, 1, 5, 5)
|
let stats = new ProjectileStats(2, 1, 5, 5)
|
||||||
let projectile = HomingProjectile.createHomingProjectile(this.world, this.getPosition(), this.player, closestTargetTo[1]!, stats, 'yellow')
|
let projectile = StraightProjectile.createStraightProjectile(this.world, this.getPosition(), closestTargetTo[1]!.getPosition(), this.player, stats, 'pink')
|
||||||
this.projectiles.push(projectile)
|
this.projectiles.push(projectile)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@@ -82,9 +127,9 @@ export class Pistol extends BasicWeapon{
|
|||||||
let pistol = new Pistol(world)
|
let pistol = new Pistol(world)
|
||||||
pistol.offset = offset;
|
pistol.offset = offset;
|
||||||
pistol.size = 5;
|
pistol.size = 5;
|
||||||
pistol.color = 'yellow';
|
pistol.color = 'brown';
|
||||||
pistol.shootInterval = 50;
|
pistol.shootInterval = 50;
|
||||||
return pistol;
|
return pistol;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user