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

View File

@@ -9,6 +9,12 @@
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
"integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg=="
},
"@types/anymatch": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
"integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
"dev": true
},
"@types/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
@@ -169,6 +175,76 @@
"@types/node": "*"
}
},
"@types/source-list-map": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
"dev": true
},
"@types/tapable": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz",
"integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
"dev": true
},
"@types/uglify-js": {
"version": "3.11.1",
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz",
"integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==",
"dev": true,
"requires": {
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"@types/webpack": {
"version": "4.41.26",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz",
"integrity": "sha512-7ZyTfxjCRwexh+EJFwRUM+CDB2XvgHl4vfuqf1ZKrgGvcS5BrNvPQqJh3tsZ0P6h6Aa1qClVHaJZszLPzpqHeA==",
"dev": true,
"requires": {
"@types/anymatch": "*",
"@types/node": "*",
"@types/tapable": "*",
"@types/uglify-js": "*",
"@types/webpack-sources": "*",
"source-map": "^0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"@types/webpack-sources": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz",
"integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/source-list-map": "*",
"source-map": "^0.7.3"
},
"dependencies": {
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
}
},
"@webassemblyjs/ast": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz",
@@ -772,6 +848,16 @@
}
}
},
"clean-webpack-plugin": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz",
"integrity": "sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A==",
"dev": true,
"requires": {
"@types/webpack": "^4.4.31",
"del": "^4.1.1"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",

View File

@@ -6,6 +6,7 @@
"scripts": {
"tsc": "tsc -w",
"build": "webpack",
"build:prod": "webpack --config webpack.config.prod.js",
"start": "webpack serve --watch"
},
"repository": {
@@ -34,5 +35,7 @@
"webpack-cli": "^4.4.0",
"webpack-dev-server": "^3.11.2"
},
"devDependencies": {}
"devDependencies": {
"clean-webpack-plugin": "^3.0.0"
}
}

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,
}

View File

@@ -0,0 +1,96 @@
-------------------------------
UBUNTU FONT LICENCE Version 1.0
-------------------------------
PREAMBLE
This licence allows the licensed fonts to be used, studied, modified and
redistributed freely. The fonts, including any derivative works, can be
bundled, embedded, and redistributed provided the terms of this licence
are met. The fonts and derivatives, however, cannot be released under
any other licence. The requirement for fonts to remain under this
licence does not require any document created using the fonts or their
derivatives to be published under this licence, as long as the primary
purpose of the document is not to be a vehicle for the distribution of
the fonts.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this licence and clearly marked as such. This may
include source files, build scripts and documentation.
"Original Version" refers to the collection of Font Software components
as received under this licence.
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to
a new environment.
"Copyright Holder(s)" refers to all individuals and companies who have a
copyright ownership of the Font Software.
"Substantially Changed" refers to Modified Versions which can be easily
identified as dissimilar to the Font Software by users of the Font
Software comparing the Original Version with the Modified Version.
To "Propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification and with or without charging
a redistribution fee), making available to the public, and in some
countries other activities as well.
PERMISSION & CONDITIONS
This licence does not grant any rights under trademark law and all such
rights are reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to propagate the Font Software, subject to
the below conditions:
1) Each copy of the Font Software must contain the above copyright
notice and this licence. These can be included either as stand-alone
text files, human-readable headers or in the appropriate machine-
readable metadata fields within text or binary files as long as those
fields can be easily viewed by the user.
2) The font name complies with the following:
(a) The Original Version must retain its name, unmodified.
(b) Modified Versions which are Substantially Changed must be renamed to
avoid use of the name of the Original Version or similar names entirely.
(c) Modified Versions which are not Substantially Changed must be
renamed to both (i) retain the name of the Original Version and (ii) add
additional naming elements to distinguish the Modified Version from the
Original Version. The name of such Modified Versions must be the name of
the Original Version, with "derivative X" where X represents the name of
the new work, appended to that name.
3) The name(s) of the Copyright Holder(s) and any contributor to the
Font Software shall not be used to promote, endorse or advertise any
Modified Version, except (i) as required by this licence, (ii) to
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
their explicit written permission.
4) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this licence, and must not be distributed
under any other licence. The requirement for fonts to remain under this
licence does not affect any document created using the Font Software,
except any version of the Font Software extracted from a document
created using the Font Software may only be distributed under this
licence.
TERMINATION
This licence becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

33
client/static/ded.html Normal file
View File

@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BlobbyStrike - U Ded</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
main {
background: #000000;
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
div {
display: block;
color: #850000;
font-size: 8rem;
}
</style>
</head>
<body>
<main>
<div>U DED...<br /><a href="/">RESPAWN</a></div>
</main>
</body>
</html>

View File

@@ -1,11 +1,11 @@
const path = require('path')
module.exports = {
mode: 'development',
entry: './src/app.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'dist',
path: path.resolve(__dirname, 'dist')
},
devtool: 'inline-source-map',
module: {

View File

@@ -0,0 +1,27 @@
const path = require('path')
const CleanPlugin = require('clean-webpack-plugin')
module.exports = {
mode: 'production',
entry: './src/app.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
devtool: 'nosources-source-map',
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
},
],
},
resolve: {
extensions: ['.ts', '.js']
},
plugins: [
new CleanPlugin.CleanWebpackPlugin()
]
}

View File

@@ -33,6 +33,15 @@ class Players {
})
}
updatePlayerHealth(id: string, health: number) {
for (let player of this.players) {
if (player.socketID === id) {
player.player.setHealth(health)
return
}
}
}
getPlayers(): Player[] {
let playerList = []
for (let player of this.players) {
@@ -56,14 +65,16 @@ class Player {
private name: string
private position: {x: number, y: number}
private color: string
private health: number
constructor(private socket: socketIO.Socket) {
this.name = 'Player#' + Math.floor(Math.random() * 10000)
this.position = {
x: Math.random()*10 - 5,
y: Math.random()*10 - 5,
x: Math.random()*500 - 250,
y: Math.random()*500 - 250,
}
this.color = '#' + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16)
this.health = 100
}
getPlayerDescription() {
@@ -72,9 +83,14 @@ class Player {
color: this.color,
position: this.position,
id: this.socket.id,
health: this.health
}
}
setHealth(hp: number) {
this.health = hp
}
setPosition(x: number, y: number) {
this.position.x = x
this.position.y = y
@@ -92,27 +108,52 @@ app.use(express.static(path.join(__dirname, '/../../client/dist')))
app.get('/', function(req, res) {
res.sendFile('index.html', { root: __dirname + '/../../client/static/'});
});
app.get('/ded', function(req, res) {
res.sendFile('ded.html', { root: __dirname + '/../../client/static/'});
});
server.listen(8089, function(){
server.listen(8089, function() {
console.log('running on port 8089');
});
io.on('connection', function(socket: socketIO.Socket) {
console.log('Player connected');
console.log(socket.id, 'connected');
let player = new Player(socket)
let otherPlayers = []
for (let p of players.getPlayers()) {
otherPlayers.push(p.getPlayerDescription())
}
players.addPlayer(socket.id, player)
socket.emit('players-info', otherPlayers)
io.emit('new-player-joined', player.getPlayerDescription())
socket.emit('your-info', player.getPlayerDescription())
socket.on('message', function(msg) {
console.log(msg)
});
socket.on('get-other-players', () => {
let otherPlayers = []
for (let p of players.getPlayers()) {
if (socket.id !== p.getPlayerDescription().id) {
otherPlayers.push(p.getPlayerDescription())
}
}
socket.emit('players-info', otherPlayers)
})
io.emit('new-player-joined', player.getPlayerDescription())
socket.on('i-moved', (position: {x: number, y: number}) => {
players.updatePlayerPosition(socket.id, {x: position.x, y: position.y})
io.emit('player-moved', {id: socket.id, position: position})
})
socket.on('disconnect', () => {
console.log(socket.id, 'disconnected')
players.removePlayer(socket.id)
io.emit('player-disconnected', socket.id)
})
socket.on('shoot', (data: {position: {x: number, y: number}, direction: {x: number, y: number}}) => {
io.emit('shoot', {id: socket.id, position: data.position, direction: data.direction})
})
socket.on('health-update', (data: {player: string, health: number}) => {
players.updatePlayerHealth(data.player, data.health)
io.emit('health-update', {id: data.player, health: data.health})
})
});