Skip to content

Commit

Permalink
feat: point arrow at leader position
Browse files Browse the repository at this point in the history
  • Loading branch information
greenpixels committed Apr 7, 2024
1 parent 9237b8f commit 5edd821
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 12 deletions.
3 changes: 3 additions & 0 deletions client/src/classes/AssetHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import GroundSprite from '@assets/spr_ground.png'
import ExplosionImageAnimation from '@assets/spr_explosion.gif'
import PlayerIdleSprite from '@assets/spr_human1.png'
import { Vector2DTO } from '@shared/index'
import ArrowSprite from '@assets/spr_arrow.png'
import AK47Sprite from '@assets/guns/spr_ak47.png'
import LugerSprite from '@assets/guns/spr_luger.png'
import M15Sprite from '@assets/guns/spr_m15.png'
Expand All @@ -25,6 +26,7 @@ export type TSpriteAssetNames = {
bullet: string
groundSprite: string
explosionImage: string
arrowSprite: string

gunAK47: string
gunLuger: string
Expand Down Expand Up @@ -54,6 +56,7 @@ export class AssetHelper {
static async loadAllSprites() {
this.assets = {
sprites: {
arrowSprite: await Assets.load(ArrowSprite),
playerWalk: await this.loadGif(PlayerWalkAnimation),
playerIdle: await Assets.load(PlayerIdleSprite),
bullet: await Assets.load(BulletSprite),
Expand Down
11 changes: 8 additions & 3 deletions client/src/handlers/ClientGameHandler/ClientGameHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class ClientGameHandler extends GameEventHandler {
inputHandler: InputHandler
groundSprite: Sprite
crownSprite: Sprite
arrowSprite: Sprite

constructor(props: ClientGameHandlerProps) {
super()
Expand All @@ -38,11 +39,15 @@ export class ClientGameHandler extends GameEventHandler {
this.groundSprite.texture.source.wrapMode = 'repeat'
this.groundSprite.scale.set(16, 9)

const iconContainer = new Container()
this.crownSprite = AssetHelper.getSpriteAsset('crownSprite')
this.arrowSprite = AssetHelper.getSpriteAsset('arrowSprite')
this.crownSprite.pivot.y = 10
iconContainer.addChild(this.crownSprite)
iconContainer.addChild(this.arrowSprite)

const objectContainer = new Container()
this.application.stage.addChild(this.groundSprite, objectContainer, this.crownSprite)
this.application.stage.addChild(this.groundSprite, objectContainer, iconContainer)

this.playerHandler = new PlayerHandler(this.updateGameInformation.bind(this), objectContainer)
this.projectileHandler = new ProjectileHandler(objectContainer)
Expand Down Expand Up @@ -80,7 +85,7 @@ export class ClientGameHandler extends GameEventHandler {
}

gameTickEvent(visiblePlayers: KeyMap<PlayerDTO>, visibleProjectiles: { [key: string]: ProjectileDTO }): void {
this.playerHandler.handlePlayerTickEvent(visiblePlayers, this.crownSprite)
this.playerHandler.handlePlayerTickEvent(visiblePlayers, this.socket.id, this.crownSprite, this.arrowSprite)
this.projectileHandler.handleProjectileTickEvent(visibleProjectiles)
this.moveCameraWithCurrentPlayer()
this.application.stage.sortChildren()
Expand All @@ -100,7 +105,7 @@ export class ClientGameHandler extends GameEventHandler {
}

playerSpawnEvent(affectedPlayers: { [key: string]: PlayerDTO }): void {
this.playerHandler.handlePlayerSpawnEvent(affectedPlayers, this.crownSprite)
this.playerHandler.handlePlayerSpawnEvent(affectedPlayers, this.socket.id, this.crownSprite, this.arrowSprite)
}

playerHurtEvent(affectedPlayers: { [key: string]: PlayerDTO }): void {
Expand Down
8 changes: 5 additions & 3 deletions client/src/handlers/PlayerHandler/PlayerHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,22 @@ describe(`Testing PlayerHandler`, () => {

function createPlayerSyncTest(
playerHandler: PlayerHandler,
handleEvent: (players: KeyMap<PlayerDTO>, crownSprite: Sprite) => void
handleEvent: (players: KeyMap<PlayerDTO>, socketId: string, crownSprite: Sprite, arrowSprite: Sprite) => void
) {
const mockPlayer = createMockPlayer('player_id_first')
test(`${handleEvent.name}: Should add a new player if the player does not yet exist on the client`, () => {
const mockSprite = { position: { x: 0, y: 0 } } as Sprite
playerHandler.addPlayer = vi.fn()
handleEvent.call(playerHandler, { [mockPlayer.id]: mockPlayer }, { position: { x: 0, y: 0 } } as Sprite)
handleEvent.call(playerHandler, { [mockPlayer.id]: mockPlayer }, mockPlayer.id, mockSprite, mockSprite)
expect(playerHandler.addPlayer).toBeCalled()
})

test(`${handleEvent.name}: Should sync players if the player already exists on the client`, () => {
playerHandler.addPlayer = vi.fn()
const mockSprite = { position: { x: 0, y: 0 } } as Sprite
const syncMock = vi.fn()
playerHandler.players = { [mockPlayer.id]: { sync: syncMock } as unknown as Player }
handleEvent.call(playerHandler, { [mockPlayer.id]: mockPlayer }, { position: { x: 0, y: 0 } } as Sprite)
handleEvent.call(playerHandler, { [mockPlayer.id]: mockPlayer }, mockPlayer.id, mockSprite, mockSprite)
expect(playerHandler.addPlayer).not.toBeCalled()
expect(syncMock).toBeCalled()
})
Expand Down
48 changes: 42 additions & 6 deletions client/src/handlers/PlayerHandler/PlayerHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Container, Sprite } from 'pixi.js'
import { Player } from '../../classes/Player'
import { PlayerDTO, KeyMap, ProjectileDTO } from '@shared/index'
import { PlayerDTO, KeyMap, ProjectileDTO, Vector2, Trigonometry } from '@shared/index'

export class PlayerHandler {
players: { [key: string]: Player } = {}
Expand All @@ -22,11 +22,16 @@ export class PlayerHandler {
this.updateCallback()
}

handlePlayerTickEvent(currentPlayers: KeyMap<PlayerDTO>, crownSprite: Sprite) {
this.syncPlayers(currentPlayers, crownSprite)
handlePlayerTickEvent(
currentPlayers: KeyMap<PlayerDTO>,
socketId: string,
crownSprite: Sprite,
arrowSprite: Sprite
) {
this.syncPlayers(currentPlayers, socketId, crownSprite, arrowSprite)
}

syncPlayers(currentPlayers: KeyMap<PlayerDTO>, crownSprite: Sprite) {
syncPlayers(currentPlayers: KeyMap<PlayerDTO>, socketId: string, crownSprite: Sprite, arrowSprite: Sprite) {
let highestScoringPlayer: Player | undefined
let highestScore = -1
Object.entries(currentPlayers).forEach(([id, playerDto]) => {
Expand All @@ -40,16 +45,47 @@ export class PlayerHandler {
highestScore = highestScoringPlayer.score
}
})
const currentPlayer = this.players[socketId]
if (!currentPlayer) return
if (highestScoringPlayer) {
crownSprite.position = {
x: highestScoringPlayer.position.x + highestScoringPlayer.sprite.width / 2,
y: highestScoringPlayer.position.y,
}
const targetPlayerPosition = new Vector2(highestScoringPlayer.position)
const currentPlayerPosition = new Vector2(currentPlayer.position)
if (
socketId === highestScoringPlayer.id ||
targetPlayerPosition.sub(currentPlayerPosition).length() < 250
) {
arrowSprite.visible = false
} else {
arrowSprite.visible = true
arrowSprite.angle = new Vector2(highestScoringPlayer.position).sub(currentPlayer.position).angle()
const arrowDistance = 120
arrowSprite.position = {
x:
currentPlayer.position.x +
currentPlayer.sprite.width / 2 +
Trigonometry.lengthdirX(arrowDistance, arrowSprite.angle),
y:
currentPlayer.position.y +
currentPlayer.sprite.height / 2 +
Trigonometry.lengthdirY(arrowDistance, arrowSprite.angle),
}
}
} else {
arrowSprite.visible = false
}
}

handlePlayerSpawnEvent(affectedPlayers: KeyMap<PlayerDTO>, crownSprite: Sprite) {
this.syncPlayers(affectedPlayers, crownSprite)
handlePlayerSpawnEvent(
affectedPlayers: KeyMap<PlayerDTO>,
socketId: string,
crownSprite: Sprite,
arrowSprite: Sprite
) {
this.syncPlayers(affectedPlayers, socketId, crownSprite, arrowSprite)
}

handlePlayerLeaveEvent(affectedPlayers: { [key: string]: PlayerDTO }) {
Expand Down

0 comments on commit 5edd821

Please sign in to comment.