Dont even remember what was done :D

This commit is contained in:
2021-01-30 20:18:24 +02:00
parent bed31b29ff
commit 93da432369
35 changed files with 958 additions and 159 deletions

41
client/src/Bullet.ts Normal file
View File

@@ -0,0 +1,41 @@
import p5 from "p5";
import OtherPlayer from "./OtherPlayer";
import { Position } from "./types";
export default class Bullet {
private timeLeftToLive = 2000;
private _position: Position
constructor(
private _shooter: OtherPlayer,
private direction: Position,
) {
this._position = {..._shooter.position}
}
get position() {
return this._position
}
get shooter() {
return this._shooter
}
move() {
this._position.x += this.direction.x
this._position.y += this.direction.y
this.timeLeftToLive -= Math.abs(this.direction.x) + Math.abs(this.direction.y)
}
get timeToLive() {
return this.timeLeftToLive
}
set timeToLive(time: number) {
this.timeLeftToLive = time
}
}

78
client/src/Game.ts Normal file
View File

@@ -0,0 +1,78 @@
import { Socket } from "socket.io-client";
import Bullet from "./Bullet";
import OtherPlayer from "./OtherPlayer";
import UserPlayer from "./UserPlayer";
import { PlayerDescription } from "./socketDataTypes";
import Pickable from "./Pickable";
export default class Game {
private player: UserPlayer
private otherPlayers: OtherPlayer[] = []
private bullets: Bullet[] = []
private items: Pickable[] = []
constructor(_socket: SocketIOClient.Socket) {
this.player = new UserPlayer(_socket.id, _socket, '', {x:0, y:0}, 'white', new Map<number, boolean>(), 100)
}
addItem(item: Pickable) {
this.items.push(item)
}
getItems() {
return this.items
}
removeItem(pickable: Pickable) {
this.items = this.items.filter((item) => {
return item !== pickable
})
}
getPlayer(): UserPlayer {
return this.player
}
setPlayer(description: PlayerDescription) {
this.player.id = description.id
this.player.name = description.name
this.player.position = description.position
this.player.color = description.color
}
addOtherPlayer(player: OtherPlayer) {
if (player.id === this.player.id) return
let oPlayer = this.otherPlayers.find((otherPlayer) => {
return player.id === otherPlayer.id
})
if (oPlayer) {
oPlayer.color = player.color
oPlayer.id = player.id
oPlayer.name = player.name
oPlayer.position = player.position
} else {
this.otherPlayers.push(player)
}
}
removeOtherPlayer(id: string) {
this.otherPlayers = this.otherPlayers.filter((player) => {
return player.id !== id
})
}
getOtherPlayers() {
return this.otherPlayers
}
getOtherPlayer(id: string) {
for (let player of this.otherPlayers) {
if (player.id === id) {
return player
}
}
return null
}
}

20
client/src/Item.ts Normal file
View File

@@ -0,0 +1,20 @@
import p5 from "p5";
export default class Item {
constructor(
private _image: p5.Image,
private _type: "HEAL" | "DAMAGE" | "DEFENCE"
) {
}
get image() {
return this._image
}
get type() {
return this._type
}
}

18
client/src/MapTile.ts Normal file
View File

@@ -0,0 +1,18 @@
import p5 from "p5";
import { Position } from "./types";
export default class MapTile {
constructor(private _image: p5.Image, private _position: Position) {
}
get image() {
return this._image
}
get position() {
return this._position
}
}

101
client/src/OtherPlayer.ts Normal file
View File

@@ -0,0 +1,101 @@
import p5 from "p5"
import Bullet from "./Bullet"
import { Position } from "./types"
export default class OtherPlayer {
private bullets: Bullet[] = []
private _damage: number
constructor(
private _id: string,
private _name: string,
private _position: Position,
private _color: string,
private _health: number
) {
this._health = 100
this._damage = 10
}
hit(bullet: Bullet, socket: SocketIOClient.Socket) {
this.health -= bullet.shooter.damage
bullet.timeToLive = -1
socket.emit('health-update', {player: this.id, health: this.health})
}
addBullet(bullet: Bullet) {
this.bullets.push(bullet)
}
getBullets() {
return this.bullets
}
removeExpiredBullets() {
this.bullets = this.bullets.filter((bullet) => {
return bullet.timeToLive > 0
})
}
draw(p5: p5, position: Position) {
p5.stroke(0, 0, 0)
p5.strokeWeight(5)
p5.fill(this.color)
p5.ellipse(position.x, position.y, 80, 80)
p5.textSize(32)
p5.fill(255, 255, 255)
p5.textAlign(p5.CENTER, p5.CENTER)
p5.text(this.name, position.x - 300, position.y - 150, 600, 50)
p5.noStroke()
p5.fill('#850000')
p5.rect(position.x - 50, position.y - 90, 100, 5)
p5.fill('#008500')
p5.rect(position.x - 50, position.y - 90, this.health, 5)
}
get health() {
return this._health
}
set health(hp: number) {
this._health = hp
}
get damage() {
return this._damage
}
get id(): string {
return this._id
}
set id(id: string) {
this._id = id
}
get position(): Position {
return this._position
}
set position(position: Position) {
this._position = position
}
get name(): string {
return this._name
}
set name(name: string) {
this._name = name
}
get color(): string {
return this._color
}
set color(color: string) {
this._color = color
}
}

22
client/src/Pickable.ts Normal file
View File

@@ -0,0 +1,22 @@
import Item from "./Item";
import { Position } from "./types";
export default class Pickable {
constructor(
private _position: Position,
private _item: Item,
) {
}
get position() {
return this._position
}
get item() {
return this._item
}
}

82
client/src/UserPlayer.ts Normal file
View File

@@ -0,0 +1,82 @@
import SocketIOClient from "socket.io-client";
import Bullet from "./Bullet";
import OtherPlayer from "./OtherPlayer";
import { Position } from "./types";
export default class UserPlayer extends OtherPlayer{
private PLAYER_SPEED = 10
private KEY_W = 87;
private KEY_A = 65;
private KEY_S = 83;
private KEY_D = 68;
constructor(
_id: string,
private _socket: SocketIOClient.Socket,
_name: string,
_position: Position,
_color: string,
private _keysPressed: Map<number, boolean>,
_health: number
) {
super(_id, _name, _position, _color, _health)
}
get socket(): SocketIOClient.Socket {
return this._socket
}
keyPressed(key: number): boolean {
return this._keysPressed.get(key) || false;
}
setKeyPressed(key: number, value: boolean) {
this._keysPressed.set(key, value)
}
clearKeysPressed() {
this._keysPressed.clear()
}
move() {
let previousPosition = {
x: this.position.x,
y: this.position.y,
}
if (this.keyPressed(this.KEY_A)) {
this.position.x -= this.PLAYER_SPEED;
}
if (this.keyPressed(this.KEY_D)) {
this.position.x += this.PLAYER_SPEED;
}
if (this.keyPressed(this.KEY_W)) {
this.position.y -= this.PLAYER_SPEED;
}
if (this.keyPressed(this.KEY_S)) {
this.position.y += this.PLAYER_SPEED;
}
if (this.position.x < -1600) {
this.position.x = -1600
}
if (this.position.y < -2000) {
this.position.y = -2000
}
if (this.position.x > 1500) {
this.position.x = 1500
}
if (this.position.y > 1900) {
this.position.y = 1900
}
if (this.position.x !== previousPosition.x || this.position.y !== previousPosition.y) {
this.socket.emit('i-moved', {x: this.position.x, y: this.position.y})
}
}
}

View File

@@ -1,112 +1,137 @@
import P5 from 'p5'
import io from 'socket.io-client'
import Game from './Game'
import MapTile from './MapTile'
import OtherPlayer from './OtherPlayer'
import prealoadResources from './preloadResources'
import setupSocketEvents from './setupSocketEvents'
import Bullet from './Bullet'
import { Position } from './types'
import Pickable from './Pickable'
import Item from './Item'
const socket = io("https://blobbystrike.ioi.lt", {secure: true});
const socket = io("https://blobbystrike.ioi.lt", {secure: true})
const game = new Game(socket)
let canvas: HTMLCanvasElement;
let images: Map<string, P5.Image>
let fonts: Map<string, P5.Font>
var tileTypes, mapTiles: any = [];
let canvas: HTMLCanvasElement
var tileTypes, mapTiles: MapTile[] = []
const PLAYER_SPEED = 10;
let shootingDelay = Date.now()
let Player = {
id: '',
name: '',
position: {x:0, y:0},
color: '#' + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16),
keysPressed: [false],
}
const VISIBLE_RANGE = 2000
const VISIBLE_RANGE_X = 1200
const VISIBLE_RANGE_Y = 700
var OtherPlayers: any = []
const PLAYER_SIZE = 80
const BULLET_SIZE = 30
var KEY_W = 87;
var KEY_A = 65;
var KEY_S = 83;
var KEY_D = 68;
let grassImage: P5.Image;
const BULLET_SHOOTING_DELAY = 100
function onKeyDown(e: any) {
Player.keysPressed[e.keyCode] = true;
game.getPlayer().setKeyPressed(e.keyCode, true)
}
function onKeyUp(e: any) {
Player.keysPressed[e.keyCode] = false;
game.getPlayer().setKeyPressed(e.keyCode, false)
}
function onContextMenu() {
Player.keysPressed = [];
game.getPlayer().clearKeysPressed()
}
function getCursorPosition(canvas: HTMLCanvasElement, event: MouseEvent) {
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left
const y = event.clientY - rect.top
return {
x: x,
y: y,
}
}
function onMouseUp(e: MouseEvent) {
if (shootingDelay > Date.now()) return
shootingDelay = Date.now() + BULLET_SHOOTING_DELAY
let pos = getCursorPosition(canvas, e)
pos.x -= parseInt(canvas.style.width) / 2
pos.y -= parseInt(canvas.style.height) / 2
let length = Math.sqrt((pos.x * pos.x) + (pos.y * pos.y))
let scale = 1 / length
scale *= 50
pos.x *= scale
pos.y *= scale
game.getPlayer().addBullet(new Bullet(game.getPlayer(), pos))
socket.emit('shoot', {position: game.getPlayer().position, direction: pos})
}
function onCanvasResize() {
var w = window.innerWidth;
var h = window.innerHeight;
var w = window.innerWidth
var h = window.innerHeight
var scale = 16/9;
var windowScale = w/h;
var windowScale = w/h
if (scale > windowScale) {
// higher
canvas.style.width = w + 'px';
canvas.style.height = (w/16*9) + 'px';
canvas.style.width = w + 'px'
canvas.style.height = (w/16*9) + 'px'
} else {
// wider
canvas.style.width = (h/9*16) + 'px';
canvas.style.height = h + 'px';
canvas.style.width = (h/9*16) + 'px'
canvas.style.height = h + 'px'
}
}
function drawPlayer(p5: P5, player: any, x: any, y: any) {
function drawPlayer(p5: P5, player: OtherPlayer, x: any, y: any) {
p5.stroke(0, 0, 0)
p5.strokeWeight(5)
// translate(-width/2, -height/2)
p5.fill(player.color)
p5.ellipse(x, y, 80, 80);
p5.textSize(32);
p5.fill(255, 255, 255);
p5.textAlign(p5.CENTER, p5.CENTER);
p5.text(player.name, x - 300,y - 100, 600, 50);
p5.ellipse(x, y, 80, 80)
p5.textSize(32)
p5.fill(255, 255, 255)
p5.textAlign(p5.CENTER, p5.CENTER)
p5.text(player.name, x - 300,y - 150, 600, 50)
p5.noStroke()
p5.fill('#850000')
p5.rect(x - 50, y - 90, 100, 5)
p5.fill('#008500')
p5.rect(x - 50, y - 90, player.health, 5)
}
function relativePosition(pos1: any, pos2: any) {
return {
x: pos2.x - pos1.x,
y: pos2.y - pos1.y,
}
function drawBullet(p5: P5, color: string, x: any, y: any) {
p5.stroke(0, 0, 0)
p5.strokeWeight(3)
p5.fill(color)
p5.ellipse(x, y, 30, 30)
}
function buildMap() {
tileTypes = {
grass: {
image: grassImage
image: images.get('grass')
}
}
for (let x = 0; x < 10; x++) {
mapTiles[x] = []
for (let y = 0; y < 6; y++) {
mapTiles[x][y] = {
tile: tileTypes.grass.image,
x: x * 380,
y: y * 380,
}
for (let x = -20; x < 20; x++) {
for (let y = -20; y < 20; y++) {
mapTiles.push(
new MapTile(
images.get('grass')!,
{
x: x * (images.get('grass')?.width || 256),
y: y * (images.get('grass')?.height || 256)
}
)
)
}
}
console.log(mapTiles)
}
function isVisible(middlePoint: any, visibleAreaSize: any, position: any, size: any) {
if (
position.x - size.width > middlePoint.x - visibleAreaSize.width/2 &&
position.x + size.width < middlePoint.x + visibleAreaSize.width/2 &&
position.y - size.height > middlePoint.y - visibleAreaSize.height/2 &&
position.y + size.height < middlePoint.y + visibleAreaSize.height/2
) {
// console.log('visible')
return true;
}
// console.log('not visible')
return false;
function isVisible(p1: Position, p2: Position) {
return Math.abs(p1.x - p2.x) < VISIBLE_RANGE_X && Math.abs(p1.y - p2.y) < VISIBLE_RANGE_Y
}
function distance(p1: any, p2: any) {
@@ -114,103 +139,134 @@ function distance(p1: any, p2: any) {
}
function drawMap(p5: P5) {
for (let xTiles of mapTiles) {
for (let yTile of xTiles) {
if (distance(Player.position, {x: yTile.x, y: yTile.y}) < 2000) {
p5.image(yTile.tile, yTile.x + p5.width/2, yTile.y + p5.height/2)
}
for (let tile of mapTiles) {
if (isVisible(game.getPlayer().position, tile.position)) {
p5.image(tile.image, tile.position.x - game.getPlayer().position.x - tile.image.width/2, tile.position.y - game.getPlayer().position.y - tile.image.height/2)
}
}
}
socket.on('your-info', function (playerData: any) {
Player.name = playerData.name;
Player.position = playerData.position;
Player.color = playerData.color;
Player.id = playerData.id;
})
socket.on('players-info', function (playersData: any) {
for (let playerData of playersData) {
if (Player.id !== playerData.id) {
OtherPlayers.push({
name: playerData.name,
position: playerData.position,
color: playerData.color,
id: playerData.id,
})
}
}
})
socket.on('new-player-joined', function (playerData: any) {
if (Player.id !== playerData.id) {
OtherPlayers.push({
name: playerData.name,
position: playerData.position,
color: playerData.color,
id: playerData.id,
})
}
})
socket.on('player-moved', function (movedPlayerData: any) {
for (let playerData of OtherPlayers) {
if (Player.id !== movedPlayerData.id && movedPlayerData.id === playerData.id) {
playerData.position = movedPlayerData.position;
}
}
})
const sketch = (p5: P5) => {
p5.setup = () => {
buildMap()
p5.createCanvas(1920, 1080);
p5.createCanvas(1920, 1080, p5.WEBGL);
canvas = document.querySelector('canvas')!
onCanvasResize()
window.addEventListener('resize', onCanvasResize)
document.addEventListener('keydown', onKeyDown)
document.addEventListener('keyup', onKeyUp)
document.addEventListener("contextmenu", onContextMenu);
document.addEventListener("contextmenu", onContextMenu)
canvas.addEventListener("mousedown", onMouseUp)
p5.textFont(fonts.get('Ubuntu')!)
game.addItem(new Pickable({x: 150, y: 150}, new Item(images.get('healthPack')!, "HEAL")))
game.addItem(new Pickable({x: 150, y: 100}, new Item(images.get('powerUp')!, "DAMAGE")))
game.addItem(new Pickable({x: 150, y: 100}, new Item(images.get('shield')!, "DEFENCE")))
}
p5.preload = () => {
grassImage = p5.loadImage('grass.png');
let resources = prealoadResources(p5)
images = resources.images
fonts = resources.fonts
setupSocketEvents(socket, game)
}
p5.draw = () => {
p5.translate(-Player.position.x, Player.position.y)
p5.background('#000000')
// p5.translate(p5.width/2, p5.height/2)
// drawing map background
drawMap(p5)
for (let otherPlayer of OtherPlayers) {
drawPlayer(p5, otherPlayer, otherPlayer.position.x + p5.width/2, -otherPlayer.position.y + p5.height/2)
// drawing items
for (let item of game.getItems()) {
p5.image(item.item.image, item.position.x - game.getPlayer().position.x, item.position.y - game.getPlayer().position.y)
}
p5.translate(Player.position.x, -Player.position.y)
drawPlayer(p5, Player, p5.width/2, p5.height/2)
p5.text(Math.floor(Player.position.x) + ':' + Math.floor(Player.position.y), p5.width/2, 50)
for (let otherPlayer of game.getOtherPlayers()) {
// going through other player list
// draw player if in range
if (isVisible(game.getPlayer().position, otherPlayer.position)) {
otherPlayer.draw(p5, {
x: otherPlayer.position.x - game.getPlayer().position.x,
y: otherPlayer.position.y - game.getPlayer().position.y
})
}
// going through bullets of that player
for (let bullet of otherPlayer.getBullets()) {
// draw bullet if in range
if (isVisible(game.getPlayer().position, bullet.position)) {
drawBullet(p5, bullet.shooter.color, bullet.position.x - game.getPlayer().position.x, bullet.position.y - game.getPlayer().position.y)
}
// move bullet
bullet.move()
// check if bullet colloides with current player
if (distance(game.getPlayer().position, bullet.position) < BULLET_SIZE + PLAYER_SIZE) {
bullet.timeToLive = -1
}
// check if bullet collides with other player
for (let otherPlayerCheck of game.getOtherPlayers()) {
if (distance(otherPlayerCheck.position, bullet.position) < BULLET_SIZE + PLAYER_SIZE) {
// check if player bullet collides with is not the player who shot the bullet
if (otherPlayerCheck.id !== bullet.shooter.id) {
bullet.timeToLive = -1
}
}
}
}
// removig bullets that has traveled far enough
otherPlayer.removeExpiredBullets()
}
let previousPosition = {
x: Player.position.x,
y: Player.position.y,
}
if (Player.keysPressed[KEY_A]) {
Player.position.x -= PLAYER_SPEED;
}
if (Player.keysPressed[KEY_D]) {
Player.position.x += PLAYER_SPEED;
}
if (Player.keysPressed[KEY_W]) {
Player.position.y += PLAYER_SPEED;
}
if (Player.keysPressed[KEY_S]) {
Player.position.y -= PLAYER_SPEED;
}
if (Player.position.x !== previousPosition.x || Player.position.y !== previousPosition.y) {
socket.emit('i-moved', {x: Player.position.x, y: Player.position.y})
// drawing current player
game.getPlayer().draw(p5, {x: 0, y: 0})
// going through current player bullets
for (let bullet of game.getPlayer().getBullets()) {
// drawing bullet if in range
if (isVisible(game.getPlayer().position, bullet.position)) {
drawBullet(p5, bullet.shooter.color, bullet.position.x - game.getPlayer().position.x, bullet.position.y - game.getPlayer().position.y)
}
// move bullet
bullet.move()
// check if bullet collides with other player
for (let otherPlayer of game.getOtherPlayers()) {
if (distance(otherPlayer.position, bullet.position) < BULLET_SIZE + PLAYER_SIZE) {
// register hit to other player
otherPlayer.hit(bullet, game.getPlayer().socket)
}
}
}
// removig bullets that has traveled far enough
game.getPlayer().removeExpiredBullets()
// drawing coordinates of the current player
p5.fill('#ffffff')
p5.stroke('#000000')
p5.textAlign(p5.LEFT, p5.TOP)
p5.text(Math.floor(game.getPlayer().position.x) + ':' + Math.floor(game.getPlayer().position.y), -p5.width/2 + 10, -p5.height/2 + 10)
// moving player depending on keys pressed
game.getPlayer().move()
}
}

View File

@@ -0,0 +1,22 @@
import P5 from 'p5'
export default function prealoadResources(p5: P5): {
images: Map<string, P5.Image>,
fonts: Map<string, P5.Font>
} {
let images = new Map<string, P5.Image>()
let fonts = new Map<string, P5.Font>()
images.set('grass', p5.loadImage('images/grass.png'))
images.set('powerUp', p5.loadImage('images/PowerUp.png'))
images.set('shield', p5.loadImage('images/Shield.png'))
images.set('healthPack', p5.loadImage('images/HealthPack.png'))
fonts.set('Ubuntu', p5.loadFont('fonts/Ubuntu/Ubuntu-Regular.ttf'))
return {
images,
fonts
};
}

View File

@@ -0,0 +1,59 @@
import SocketIOClient from 'socket.io-client'
import Bullet from './Bullet'
import Game from './Game'
import OtherPlayer from './OtherPlayer'
import { BulletData, PlayerDescription } from './socketDataTypes'
import { Position } from './types'
export default function setupSocketEvents(socket: SocketIOClient.Socket, game: Game) {
socket.on('your-info', function (playerData: PlayerDescription) {
let player = game.getPlayer()
player.color = playerData.color
player.id = playerData.id
player.name = playerData.name
player.position = playerData.position
player.health = playerData.health
socket.emit('get-other-players')
})
socket.on('players-info', function (playersData: PlayerDescription[]) {
for (let playerData of playersData) {
game.addOtherPlayer(new OtherPlayer(playerData.id, playerData.name, playerData.position, playerData.color, playerData.health))
}
})
socket.on('new-player-joined', function (playerData: PlayerDescription) {
if (game.getPlayer().id !== playerData.id) {
game.addOtherPlayer(new OtherPlayer(playerData.id, playerData.name, playerData.position, playerData.color, playerData.health))
}
})
socket.on('player-moved', function (movedPlayerData: {id: string, position: Position}) {
for (let playerData of game.getOtherPlayers()) {
if (movedPlayerData.id === playerData.id) {
playerData.position = movedPlayerData.position;
}
}
})
socket.on('player-disconnected', function (disconnectedPlayer: string) {
game.removeOtherPlayer(disconnectedPlayer)
})
socket.on('shoot', (data: BulletData) => {
let otherPlayer = game.getOtherPlayer(data.id)
if (otherPlayer) {
otherPlayer.addBullet(new Bullet(otherPlayer, data.direction))
}
})
socket.on('health-update', (data: {id: string, health: number}) => {
let otherPlayer = game.getOtherPlayer(data.id)
if (otherPlayer) {
otherPlayer.health = data.health
}
if (game.getPlayer().socket.id === data.id) {
game.getPlayer().health = data.health
if (data.health <= 0) {
window.location.href = '/ded';
}
}
})
}

View File

@@ -0,0 +1,18 @@
import { Position } from "./types"
export type PlayerDescription = {
name: string,
color: string,
position: {
x: number,
y: number,
},
id: string,
health: number,
}
export type BulletData = {
id: string,
position: Position,
direction: Position
}

4
client/src/types.ts Normal file
View File

@@ -0,0 +1,4 @@
export type Position = {
x: number,
y: number,
}