Skip to content

Commit

Permalink
feat: add shot adjust
Browse files Browse the repository at this point in the history
  • Loading branch information
K9 committed Jul 29, 2024
1 parent ee97edb commit 690cad3
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 12 deletions.
7 changes: 4 additions & 3 deletions src/Game/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import ZombieSpawner from "./Spawner/ZombieSpawner";
import ZombieBossSpawner from "./Spawner/ZombieBossSpawner";
import BulletSpawner from "./Spawner/BulletSpawner";
import { calculateAngle, calculateRangeAngles } from "./utils";
import { calculateAngle, calculateInterceptAngle, calculateRangeAngles } from "./utils";

class Game {
public canvas: HTMLCanvasElement;
Expand Down Expand Up @@ -333,11 +333,12 @@ class Game {

shootBullet() {
const player = this.player;
const target = this.shotTargetZombie;
const target = this.shotTargetZombie!;
const angles = calculateRangeAngles(player.getTrajectoryCount());

for (let angle of angles) {
const adjustedAngle = calculateAngle(player, target);
// const adjustedAngle = calculateAngle(player, target);
const adjustedAngle = calculateInterceptAngle(player, target, player.getSpeed(), target.getSpeed());
const enhanced: BulletEnhancedInterface = {
...DEFAULT_BULLET_ENHANCE_OBJECT,
damage: player.damage,
Expand Down
8 changes: 4 additions & 4 deletions src/Game/GameObject/Bullet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class Bullet extends GameObject {
}

_calculateVelocityVector(): VelocityVector {
const vx = this.speed * Math.cos(this.angle);
const vy = this.speed * Math.sin(this.angle);
const vx = -this.speed * Math.cos(this.angle);
const vy = -this.speed * Math.sin(this.angle);
return { vx, vy };
}

Expand Down Expand Up @@ -129,8 +129,8 @@ class Bullet extends GameObject {
}

update() {
this.x -= this.velocity.vx;
this.y -= this.velocity.vy;
this.x += this.velocity.vx;
this.y += this.velocity.vy;
}

draw(ctx: CanvasRenderingContext2D) {
Expand Down
12 changes: 10 additions & 2 deletions src/Game/GameObject/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Zombie from "./Zombie";
import { GameObjectEnum } from "../enum";
import { DEFAULT_BULLET_ENHANCE_OBJECT, LEVEL_UP_KILL_COUNT } from "../constants";
import { BulletConstructorProps, BulletEnhancedInterface, PlayerEnhancedInterface } from "../type";
import { calculateInterceptAngle } from "../utils";

class Player extends GameObject {
damage: number;
Expand All @@ -15,6 +16,7 @@ class Player extends GameObject {
// 连击数
private comboTimes: number;
private pierceTimes: number;
private speed: number;
constructor(x: number, y: number, enhanced: PlayerEnhancedInterface) {
super(x, y, enhanced.radius, GameObjectEnum.PLAYER);
this.damage = enhanced.damage;
Expand All @@ -24,6 +26,7 @@ class Player extends GameObject {
this.collisionWallTimes = enhanced.collisionWallTimes;
this.comboTimes = enhanced.comboTimes;
this.pierceTimes = enhanced.pierceTimes;
this.speed = enhanced.speed;
}

getCollisionWallTimes() {
Expand Down Expand Up @@ -89,6 +92,10 @@ class Player extends GameObject {
return this.killCount;
}

getSpeed() {
return this.speed;
}

levelUp() {
if (this.level > 2) return;
console.log("level up!!!");
Expand Down Expand Up @@ -132,11 +139,12 @@ class Player extends GameObject {
return angles;
}

shotBullets(target: GameObject | null): BulletConstructorProps[] {
shotBullets(target: Zombie): BulletConstructorProps[] {
const bulletsProps: BulletConstructorProps[] = [];
const angles = this._calculateRangeAngles();
for (let angle of angles) {
const adjustedAngle = this._calculateAngle(target);
// const adjustedAngle1 = this._calculateAngle(target);
const adjustedAngle = calculateInterceptAngle(this, target, this.speed, target.getSpeed());
const enhanced: BulletEnhancedInterface = {
...DEFAULT_BULLET_ENHANCE_OBJECT,
damage: this.damage,
Expand Down
5 changes: 4 additions & 1 deletion src/Game/GameObject/Zombie.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import GameObject from "./GameObject";
import { GameObjectEnum } from "../enum";
import { ZombieEnhanceInterface } from "../type";
import { Circle } from "@timohausmann/quadtree-ts";

class Zombie extends GameObject {
private speed: number;
Expand All @@ -14,6 +13,10 @@ class Zombie extends GameObject {
this.is_boss = enhanced.isBoss;
}

getSpeed() {
return this.speed;
}

update() {
this.y += this.speed; // Zombies move down
}
Expand Down
36 changes: 36 additions & 0 deletions src/Game/Object/Vector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Vector {
x: number;
y: number;

constructor(x: number, y: number) {
this.x = x;
this.y = y;
}

add(v: Vector) {
return new Vector(this.x + v.x, this.y + v.y);
}

subtract(v: Vector) {
return new Vector(this.x - v.x, this.y - v.y);
}

multiply(scalar: number) {
return new Vector(this.x * scalar, this.y * scalar);
}

magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}

normalize() {
const mag = this.magnitude();
return new Vector(this.x / mag, this.y / mag);
}

getRad() {
return Math.atan2(this.y, this.x);
}
}

export default Vector;
5 changes: 3 additions & 2 deletions src/Game/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const DEFAULT_BULLET_ENHANCE_OBJECT: BulletEnhancedInterface = {
radius: 3,
angle: Math.PI / 2,
damage: 30,
speed: 10,
speed: -10,
canExplode: true,
explodeRadius: 20,
explodeDamage: 1,
Expand All @@ -37,7 +37,8 @@ export const DEFAULT_PLAYER_ENHANCE_OBJECT: PlayerEnhancedInterface = {
trajectoryCount: 1,
collisionWallTimes: 0,
comboTimes: 1,
pierceTimes: 2
pierceTimes: 2,
speed: 10
};

export const LEVEL_UP_KILL_COUNT = 2 * 6;
Expand Down
1 change: 1 addition & 0 deletions src/Game/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface PlayerEnhancedInterface {
collisionWallTimes: number;
comboTimes: number;
pierceTimes: number;
speed: number;
}

export interface VelocityVector {
Expand Down
46 changes: 46 additions & 0 deletions src/Game/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Circle } from "@timohausmann/quadtree-ts";
import Vector from "./Object/Vector";

export const getRandomRange = (start: number, end: number): number => {
if (start > end) {
Expand Down Expand Up @@ -33,3 +34,48 @@ export const calculateAngle = (
const dy = source.y - target.y;
return Math.atan2(dy, dx);
};

export const calculateInterceptAngle = (
source: Circle,
target: Circle | null,
sourceSpeed: number,
targetSpeed: number
): number => {
if (!target) return Math.PI / 2;
const sourcePos = new Vector(source.x, source.y);
const targetPos = new Vector(target.x, target.y);
const targetVel = new Vector(0, targetSpeed);
const relativePos = targetPos.subtract(sourcePos);
const effectiveRadius = source.r + target.r;
// 修改二次方程系数
const a =
sourceSpeed * sourceSpeed -
targetVel.x * targetVel.x -
targetVel.y * targetVel.y;
const b = 2 * (targetVel.x * relativePos.x + targetVel.y * relativePos.y);
const c =
-relativePos.x * relativePos.x -
relativePos.y * relativePos.y +
effectiveRadius * effectiveRadius;

// 求解二次方程
const discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return Math.PI / 2;
}

const t1 = (-b + Math.sqrt(discriminant)) / (2 * a);
const t2 = (-b - Math.sqrt(discriminant)) / (2 * a);
const t = Math.max(t1, t2);

if (t < 0) {
return Math.PI / 2;
}

const interceptPos = targetPos.add(targetVel.multiply(t));

// const bulletVec = interceptPos.subtract(sourcePos).multiply(1 / t); // 可以不归一化直接计算
const bulletVec = interceptPos.subtract(sourcePos);

return bulletVec.getRad();
};

0 comments on commit 690cad3

Please sign in to comment.