Skip to content

Commit

Permalink
feat: add combo
Browse files Browse the repository at this point in the history
  • Loading branch information
K9 committed Jul 24, 2024
1 parent c6d2138 commit 81db080
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 78 deletions.
29 changes: 15 additions & 14 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useEffect, useRef } from 'react';
import { useVisibile } from './hooks/useVisible';
import Game from './Game/Game';
// import { Game } from './Space';
import { useEffect, useRef } from "react";
import { useVisibile } from "./hooks/useVisible";
import Game from "./Game/Game";

const TaskDemo = () => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
Expand Down Expand Up @@ -30,13 +29,12 @@ const TaskDemo = () => {
}
};


useEffect(() => {
const game = gameRef.current;
if (game?.isRunning() && !visible) {
game.pause();
}
}, [visible])
}, [visible]);

useEffect(() => {
const shot = () => {
Expand All @@ -48,23 +46,26 @@ const TaskDemo = () => {
};

if (canvasRef.current) {
canvasRef.current.addEventListener('click', shot);
canvasRef.current.addEventListener("click", shot);
}


return () => {
if (canvasRef.current) {
canvasRef.current.removeEventListener('click', shot);
canvasRef.current.removeEventListener("click", shot);
}
};
}, [canvasRef.current]);

return (
<div>
<button onClick={start}>Start Game</button>
<button onClick={pause}>Pause Game</button>
<canvas ref={canvasRef} width="640" height="480"></canvas>
</div>
<>
<div className="canvas">
<canvas ref={canvasRef} width="640" height="480"></canvas>
</div>
<div className="btn-box">
<button onClick={start}>Start Game</button>
<button onClick={pause}>Pause Game</button>
</div>
</>
);
};

Expand Down
105 changes: 66 additions & 39 deletions src/Game/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import Zombie from "./GameObject/Zombie";
import Bullet from "./GameObject/Bullet";
import Player from "./GameObject/Player";
import GameObject from "./GameObject/GameObject";
import { BoundInterface, BulletEnhancedInterface, ZombieEnhanceInterface } from "./type";
import {
BoundInterface,
BulletEnhancedInterface,
Position,
ZombieEnhanceInterface,
} from "./type";
import {
DEFAULT_BULLET_ENHANCE_OBJECT,
DEFAULT_ZOMBIE_BOSS_ENHANCE_OBJECT,
DEFAULT_ZOMBIE_ENHANCE_OBJECT,
} from "./constants";
import ZombieSpawner from "./Spawner/ZombieSpawner";
Expand Down Expand Up @@ -53,19 +59,19 @@ class Game {
this.bullets = new Map();
this.explodeBullets = new Map();
this.running = false;
this.player = new Player(this.canvas.width / 2, this.canvas.height - 20);
this.player = new Player(this.canvas.width / 2, this.canvas.height);
this.shotTargetZombie = null;

this.zombieSpawner = new ZombieSpawner(this, 600);
this.zombieBossSpawner = new ZombieBossSpawner(this, 10 * 1000);
this.bulletSpawner = new BulletSpawner(this, 200);
this.bulletSpawner = new BulletSpawner(this, 400);
this.active = false;
this.canvasBounds = {
left: 0,
right: this.canvas.width,
top: 0,
bottom: this.canvas.height,
};
left: 0,
right: this.canvas.width,
top: 0,
bottom: this.canvas.height,
};
}

isActive() {
Expand Down Expand Up @@ -160,24 +166,24 @@ class Game {
this.shotTargetZombie = null;

for (let [, zombie] of this.zombies) {
zombie.update();
if (zombie.isOffCanvas(this.canvasBounds)) {
this.zombies.delete(zombie.count);
this.quadTree.remove(zombie, true);
} else {
this.updateTargetZombie(this.canvas.height - 20, zombie);
this.quadTree.update(zombie, true);
// this.quadTree.insert(zombie);
}
zombie.update();
if (zombie.isOffCanvas(this.canvasBounds)) {
this.zombies.delete(zombie.count);
this.quadTree.remove(zombie, true);
} else {
this.updateTargetZombie(this.canvas.height - 20, zombie);
this.quadTree.update(zombie, true);
// this.quadTree.insert(zombie);
}
for (let [, bullet] of this.bullets) {
bullet.checkBound(this.canvasBounds);
bullet.update();

if (bullet.isOffCanvas(this.canvasBounds) && !bullet.hasLeftCollision()) {
this.bullets.delete(bullet.count);
}
}
for (let [, bullet] of this.bullets) {
bullet.checkBound(this.canvasBounds);
bullet.update();

if (bullet.isOffCanvas(this.canvasBounds) && !bullet.hasLeftCollision()) {
this.bullets.delete(bullet.count);
}
}
}

draw() {
Expand Down Expand Up @@ -261,6 +267,22 @@ class Game {
return Math.atan2(dy, dx);
}

predictZombiePosition(
zombie: Zombie | null,
player: Player,
speed: number
): Position | null {
if (!zombie || !player) return null;
const timeToHit =
Math.sqrt((zombie.x - player.x) ** 2 + (zombie.y - player.y) ** 2) /
speed;
const zombieSpeed = zombie.getSpeed();
// 暂时不考虑x轴因素
const predictedX = zombie.x + 0 * timeToHit;
const predictedY = zombie.y + zombieSpeed * timeToHit;
return { x: predictedX, y: predictedY };
}

drawQuadtree(node: Quadtree<Circle>, ctx: CanvasRenderingContext2D) {
if (node.nodes.length === 0) {
ctx.strokeStyle = `rgba(127,255,212,0.25)`;
Expand All @@ -277,24 +299,33 @@ class Game {
}
}

shootBullet(bulletCount: number = 1) {
shootBullet() {
const player = this.player;
const target = this.shotTargetZombie;
const angles = calculateRangeAngles(bulletCount);
const angles = calculateRangeAngles(player.trajectoryCount);
const fireTimes = player.fireTimes;

for (let angle of angles) {
// const predictedPosition = this.predictZombiePosition(target, player, DEFAULT_BULLET_ENHANCE_OBJECT.speed);
const adjustedAngle = this.calculateAngle(player, target);
const enhanced: BulletEnhancedInterface = {
...DEFAULT_BULLET_ENHANCE_OBJECT,
damage: player.damage,
angle: this.calculateAngle(player, target) + angle,
collisionCanvasTimes: player.collisionCanvasTimes
angle: adjustedAngle + angle,
collisionWallTimes: player.collisionWallTimes,
};
const newBullet = new Bullet(
this.canvas.width / 2,
this.canvas.height - 20,
enhanced
);
this.bullets.set(newBullet.count, newBullet);

for (let i = fireTimes - 1; i >= 0; i--) {
const deltaHeight = 20 * i;
const deltaWidth = deltaHeight / Math.tan(enhanced.angle);

const newBullet = new Bullet(
player.getStandX() - deltaWidth,
player.getStandY() - deltaHeight,
enhanced
);
this.bullets.set(newBullet.count, newBullet);
}
}
}

Expand All @@ -309,11 +340,7 @@ class Game {

addZombieBoss(x: number) {
const enhanced: ZombieEnhanceInterface = {
...DEFAULT_ZOMBIE_ENHANCE_OBJECT,
radius: 20,
speed: 1,
health: 500,
isBoss: true,
...DEFAULT_ZOMBIE_BOSS_ENHANCE_OBJECT,
};
const newZombie = new Zombie(x, 0, enhanced);
this.zombies.set(newZombie.count, newZombie);
Expand Down
12 changes: 6 additions & 6 deletions src/Game/GameObject/Bullet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ class Bullet extends GameObject {
public damage: number;
public explodeDamage: number;
private velocity: VelocityVector;
private collisionCanvasTimes: number;
private collisionWallTimes: number;
constructor(
x: number,
y: number,
enhanced: BulletEnhancedInterface = DEFAULT_BULLET_ENHANCE_OBJECT
) {
super(x, y, enhanced.radius, GameObjectEnum.BULLET);
this.explodeRadius = enhanced.explodeRadius;
this.collisionCanvasTimes = enhanced.collisionCanvasTimes;
this.collisionWallTimes = enhanced.collisionWallTimes;
this.angle = enhanced.angle;
this.damage = enhanced.damage;
this.explodeDamage = enhanced.explodeDamage;
Expand All @@ -27,7 +27,7 @@ class Bullet extends GameObject {
}

hasLeftCollision() {
return this.collisionCanvasTimes > 0;
return this.collisionWallTimes > 0;
}

_calculateVelocityVector(): VelocityVector {
Expand All @@ -54,14 +54,14 @@ class Bullet extends GameObject {

checkBound(bound: BoundInterface) {
// 如果碰撞次数小于0,直接返回
if (this.collisionCanvasTimes <= 0) return;
if (this.collisionWallTimes <= 0) return;
if (this._isCollisionX(bound.left, bound.right)) {
this._updateVelocityXVector();
this.collisionCanvasTimes--;
this.collisionWallTimes--;
}
if (this._isCollisionY(bound.top, bound.bottom)) {
this._updateVelocityYVector();
this.collisionCanvasTimes--;
this.collisionWallTimes--;
}
}

Expand Down
43 changes: 30 additions & 13 deletions src/Game/GameObject/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,43 @@ class Player extends GameObject {
damage: number;
killCount: number;
level: number;
bulletCount: number;
collisionCanvasTimes: number;
trajectoryCount: number;
collisionWallTimes: number;
fireTimes: number;
firePosition: number;
constructor(x: number, y: number) {
super(x, y, 10, GameObjectEnum.PLAYER);
this.damage = 30;
this.killCount = 0;
this.level = 1;
this.bulletCount = 1;
this.collisionCanvasTimes = 0;
this.trajectoryCount = 1;
this.collisionWallTimes = 0;
this.fireTimes = 1;
this.firePosition = 20;
}

updateBulletCount(bulletCount: number) {
this.bulletCount = bulletCount;
getStandX() {
return this.x;
}

getStandY() {
return this.y - this.firePosition;
}

updateFireTimes(fireTimes: number) {
this.fireTimes = fireTimes;
}

updatetrajectoryCount(trajectoryCount: number) {
this.trajectoryCount = trajectoryCount;
}

updateDamage(damage: number) {
this.damage = damage;
}

updateCollisionCanvasTimes(times: number) {
this.collisionCanvasTimes = times;
this.collisionWallTimes = times;
}

addKill(z: Zombie) {
Expand All @@ -36,9 +52,9 @@ class Player extends GameObject {
} else {
this.killCount++;
}
// 打死100个升级
// 打死N个升级
if (
this.killCount % (LEVEL_UP_KILL_COUNT * Math.pow(4, this.level - 1)) ===
this.killCount % (LEVEL_UP_KILL_COUNT * Math.pow(6, this.level - 1)) ===
0
) {
this.levelUp();
Expand All @@ -50,17 +66,18 @@ class Player extends GameObject {
}

levelUp() {
if (this.level > 3) return;
if (this.level > 0) return;
console.log("level up!!!");
this.level++;
this.updateDamage(this.damage + 10);
this.updateBulletCount(this.bulletCount + 1);
this.updateCollisionCanvasTimes(this.collisionCanvasTimes + 1);
this.updatetrajectoryCount(this.trajectoryCount + 1);
this.updateCollisionCanvasTimes(this.collisionWallTimes + 1);
this.updateFireTimes(this.fireTimes + 1);
}

draw(ctx: CanvasRenderingContext2D) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.arc(this.x, this.y - this.firePosition, this.r, 0, Math.PI * 2);
ctx.fillStyle = "blue";
ctx.fill();
}
Expand Down
4 changes: 4 additions & 0 deletions src/Game/GameObject/Zombie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,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
3 changes: 1 addition & 2 deletions src/Game/Spawner/BulletSpawner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ class BulletSpawner extends Spawner {
super(game, spawnInterval);
}
spawn() {
const player = this.game.getPlayer();
this.game.shootBullet(player.bulletCount);
this.game.shootBullet();
}
}

Expand Down
Loading

0 comments on commit 81db080

Please sign in to comment.