mirror of
https://github.com/Sheldan/canvas.git
synced 2026-01-01 14:58:51 +00:00
survivors: adding health regen and simple particle system
This commit is contained in:
@@ -3,6 +3,8 @@ import {Vector} from "./base.ts";
|
||||
import {fillDot, getCoordinatesSplit} from "./utils.ts";
|
||||
import {PlayerStats} from "./stats.ts";
|
||||
import {PlayerStatus} from "./status.ts";
|
||||
import {World} from "./World.ts";
|
||||
import {HealingParticle} from "./particles.ts";
|
||||
|
||||
export class Player implements Drawable, Acting, Healthy {
|
||||
private _position: Vector;
|
||||
@@ -14,10 +16,13 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
private _status: PlayerStatus;
|
||||
private _weapons: Weapon[] = []
|
||||
private _items: Item[] = []
|
||||
private _healTick: number = 0;
|
||||
private static readonly HEAL_TICK_INTERVAL = 20;
|
||||
private _world: World;
|
||||
|
||||
// temp
|
||||
private _speed: Vector;
|
||||
|
||||
private _toHeal: number = 0;
|
||||
|
||||
constructor(position: Vector) {
|
||||
this._position = position;
|
||||
@@ -61,6 +66,10 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
this._items.push(item)
|
||||
}
|
||||
|
||||
set world(value: World) {
|
||||
this._world = value;
|
||||
}
|
||||
|
||||
move(direction: Vector) {
|
||||
this._position = this.position.add(direction)
|
||||
}
|
||||
@@ -145,5 +154,23 @@ export class Player implements Drawable, Acting, Healthy {
|
||||
level() {
|
||||
return this.status.level
|
||||
}
|
||||
|
||||
isHurt() {
|
||||
return this.health < this._effectiveStats.health
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
this._healTick += 1;
|
||||
if((this._healTick % Player.HEAL_TICK_INTERVAL) == 0 && this.isHurt()) {
|
||||
let healed = this._effectiveStats.healthRegen / seconds
|
||||
this._toHeal += healed;
|
||||
if(this._toHeal >= 1) {
|
||||
let toHealNow = this._toHeal - (this._toHeal % 1);
|
||||
this._toHeal -= toHealNow;
|
||||
this.heal(toHealNow);
|
||||
HealingParticle.spawnHealingParticle(this._world, toHealNow, this.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,20 +2,25 @@ import {Enemy} from "./Enemies.ts";
|
||||
import {Player} from "./Player.ts";
|
||||
import {Projectile } from "./projectile.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import type {Drop, Placeable} from "./interfaces.ts";
|
||||
import type {Drop, Particle, Placeable} from "./interfaces.ts";
|
||||
|
||||
export class World {
|
||||
private _enemies: ObjectContainer<Enemy> = new ObjectContainer<Enemy>()
|
||||
private _projectiles: ObjectContainer<Projectile> = new ObjectContainer<Projectile>();
|
||||
private _drops: ObjectContainer<Drop> = new ObjectContainer<Drop>();
|
||||
private _particles: ObjectContainer<Particle> = new ObjectContainer();
|
||||
private _player: Player;
|
||||
private readonly _ctx: CanvasRenderingContext2D;
|
||||
private _size: Vector;
|
||||
private _tick: number = 0;
|
||||
private static readonly TICK_INTERVAL = 10;
|
||||
private timeStamp: Date;
|
||||
|
||||
constructor(player: Player, ctx: CanvasRenderingContext2D, size: Vector) {
|
||||
this._player = player;
|
||||
this._ctx = ctx;
|
||||
this._size = size;
|
||||
this.timeStamp = new Date();
|
||||
}
|
||||
|
||||
enemiesAct() {
|
||||
@@ -25,12 +30,15 @@ export class World {
|
||||
this._projectiles.clean()
|
||||
this._drops.items.forEach(drop => drop.act())
|
||||
this._drops.clean()
|
||||
this._particles.items.forEach(particle => particle.act())
|
||||
this._particles.clean()
|
||||
}
|
||||
|
||||
draw() {
|
||||
this._enemies.items.forEach(enemy => enemy.draw(this._ctx))
|
||||
this._drops.items.forEach(drop => drop.draw(this._ctx))
|
||||
this._projectiles.items.forEach(projectile => projectile.draw(this._ctx))
|
||||
this._particles.items.forEach(particle => particle.draw(this._ctx))
|
||||
this._player.draw(this._ctx);
|
||||
}
|
||||
|
||||
@@ -38,6 +46,10 @@ export class World {
|
||||
this._projectiles.add(projectile)
|
||||
}
|
||||
|
||||
addParticle(particle: Particle) {
|
||||
this._particles.add(particle)
|
||||
}
|
||||
|
||||
addDrop(drop: Drop) {
|
||||
this._drops.add(drop)
|
||||
}
|
||||
@@ -46,6 +58,10 @@ export class World {
|
||||
this._drops.scheduleRemoval(drop)
|
||||
}
|
||||
|
||||
removeParticle(particle: Particle) {
|
||||
this._particles.scheduleRemoval(particle)
|
||||
}
|
||||
|
||||
removeEnemy(enemy: Enemy) {
|
||||
this._enemies.scheduleRemoval(enemy)
|
||||
}
|
||||
@@ -69,11 +85,21 @@ export class World {
|
||||
return Math.max(this.size.x, this.size.y)
|
||||
}
|
||||
|
||||
|
||||
get size(): Vector {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
tick() {
|
||||
this._tick += 1;
|
||||
if((this._tick % World.TICK_INTERVAL) == 0) {
|
||||
let currentTimeStamp = new Date();
|
||||
let seconds = (currentTimeStamp.getTime() - this.timeStamp.getTime()) / 1000;
|
||||
this._player.tick(seconds, this._tick);
|
||||
this._particles.items.forEach(particle => particle.tick(seconds, this._tick))
|
||||
this.timeStamp = currentTimeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
outside(position: Vector): boolean {
|
||||
return position.x > this.size.x || position.y > this.size.y || position.x < 0 || position.y < 0
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ export abstract class BasicDrop implements Drop {
|
||||
return this.size
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MoneyDrop extends BasicDrop {
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {World} from "./World.ts";
|
||||
|
||||
export interface Acting {
|
||||
act()
|
||||
tick(seconds: number, tick: number)
|
||||
}
|
||||
|
||||
export interface Healthy {
|
||||
@@ -33,6 +34,10 @@ export interface Drop extends Drawable, Acting {
|
||||
pickup()
|
||||
}
|
||||
|
||||
export interface Particle extends Drawable, Placeable, Acting {
|
||||
|
||||
}
|
||||
|
||||
export interface Placeable {
|
||||
move(any?: any)
|
||||
getSize();
|
||||
|
||||
@@ -9,7 +9,6 @@ import {HUD} from "./ui.ts";
|
||||
import {Pistol} from "./weapons.ts";
|
||||
import {ItemManagement} from "./items.ts";
|
||||
|
||||
|
||||
let hud: HUD;
|
||||
let world: World;
|
||||
let config: Config;
|
||||
@@ -39,6 +38,7 @@ function updateCanvas() {
|
||||
ctx.clearRect(0, 0, world.size.x, world.size.y);
|
||||
hud.draw(ctx)
|
||||
if(!state.ended) {
|
||||
world.tick()
|
||||
world.enemiesAct()
|
||||
world.player.act()
|
||||
world.draw()
|
||||
@@ -108,6 +108,7 @@ docReady(function () {
|
||||
let player = Player.generatePlayer(new Vector(window.innerWidth /2, window.innerHeight / 2));
|
||||
|
||||
world = new World(player, ctx, new Vector(window.innerWidth, window.innerHeight));
|
||||
player.world = world; // not sure if this is great design
|
||||
state = new WorldState();
|
||||
|
||||
setInterval(() => {
|
||||
|
||||
69
absurd-survivors/src/particles.ts
Normal file
69
absurd-survivors/src/particles.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import type {Particle} from "./interfaces.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {World} from "./World.ts";
|
||||
|
||||
abstract class BaseParticle implements Particle {
|
||||
protected _position: Vector;
|
||||
protected world: World;
|
||||
|
||||
|
||||
constructor(position: Vector, world: World) {
|
||||
this._position = position.clone();
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
this._position = this._position.add(new Vector(0, -0.5))
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
}
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class HealingParticle extends BaseParticle {
|
||||
private healthAmount: number;
|
||||
private secondsToDisplay: number = 2;
|
||||
private alreadyDisplayed: number = 0;
|
||||
|
||||
constructor(position: Vector, world: World, healthAmount: number) {
|
||||
super(position, world);
|
||||
this.healthAmount = healthAmount;
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.fillText(this.healthAmount + '', this._position.x, this._position.y);
|
||||
}
|
||||
|
||||
static spawnHealingParticle(world: World, health: number, position: Vector) {
|
||||
world.addParticle(this.createHealingParticle(world, health, position))
|
||||
}
|
||||
|
||||
static createHealingParticle(world: World, health: number, position: Vector) {
|
||||
let healingParticle = new HealingParticle(position, world, health)
|
||||
return healingParticle
|
||||
}
|
||||
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
this.alreadyDisplayed += seconds;
|
||||
if(this.alreadyDisplayed > this.secondsToDisplay) {
|
||||
this.world.removeParticle(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export class PlayerStats {
|
||||
private _pullRange: number;
|
||||
private _weaponRange: number;
|
||||
private _weaponRangeFactor: number;
|
||||
private _healthRegen: number;
|
||||
|
||||
constructor() {
|
||||
this._speed = 3;
|
||||
@@ -15,6 +16,7 @@ export class PlayerStats {
|
||||
this._pullRange = 150;
|
||||
this._weaponRange = 250;
|
||||
this._weaponRangeFactor = 1;
|
||||
this._healthRegen = 0.001;
|
||||
}
|
||||
|
||||
resetToBasic() {
|
||||
@@ -22,7 +24,8 @@ export class PlayerStats {
|
||||
this._health = 0;
|
||||
this._pullRange = 0;
|
||||
this._weaponRange = 0;
|
||||
this._weaponRangeFactor = 1
|
||||
this._weaponRangeFactor = 1;
|
||||
this._healthRegen = 0.1;
|
||||
}
|
||||
|
||||
increaseLevel() {
|
||||
@@ -31,6 +34,7 @@ export class PlayerStats {
|
||||
this._pullRange *= 1.1;
|
||||
this._weaponRange *= 1.25
|
||||
this._weaponRangeFactor += 0.1
|
||||
this._healthRegen += 0.1
|
||||
}
|
||||
|
||||
mergeStats(otherStats: PlayerStats) {
|
||||
@@ -39,6 +43,7 @@ export class PlayerStats {
|
||||
this._pullRange += otherStats._pullRange;
|
||||
this._weaponRange += otherStats._weaponRange
|
||||
this._weaponRangeFactor += otherStats._weaponRangeFactor;
|
||||
this._healthRegen += otherStats._healthRegen;
|
||||
}
|
||||
|
||||
clone() {
|
||||
@@ -91,6 +96,10 @@ export class PlayerStats {
|
||||
return this._weaponRange
|
||||
}
|
||||
|
||||
get healthRegen(): number {
|
||||
return this._healthRegen;
|
||||
}
|
||||
|
||||
get effectiveWeaponRange(): number {
|
||||
return this._weaponRange * this._weaponRangeFactor;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user