lots of stuff, scores system, better collisions, highscores, scoreboard, player counter, etc.

This commit is contained in:
2021-01-31 14:25:20 +02:00
parent c7de79fbc4
commit 15c8e91272
27 changed files with 937 additions and 107667 deletions

View File

@@ -2720,6 +2720,11 @@
"resolved": "https://registry.npmjs.org/p5/-/p5-1.2.0.tgz",
"integrity": "sha512-om9CSZXjw+BdC/u474nUtrVXAqeSRHNBDteDpIhQqgypziE+hh9BUc/YNl3RT5rX3kNtQlLes2S2sRqFU+S+JA=="
},
"p5.collide2d": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/p5.collide2d/-/p5.collide2d-0.7.3.tgz",
"integrity": "sha512-df25EMJqifEzXI2POsU+9jmTiXNiOijXYlo7VoEzA8nL1uS6lw9sM1dMBisI+F6owrxMoNOKLW53r2VpivD98w=="
},
"parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",

View File

@@ -27,6 +27,7 @@
"cors": "^2.8.5",
"express": "^4.17.1",
"p5": "^1.2.0",
"p5.collide2d": "^0.7.3",
"socket.io": "^3.1.0",
"socket.io-client": "^3.1.0",
"ts-loader": "^8.0.14",

View File

@@ -25,7 +25,7 @@ export default class Bullet {
draw(p5: p5, position: Position) {
p5.stroke(0, 0, 0)
p5.strokeWeight(3)
p5.strokeWeight(2)
p5.fill(this._shooter.color)
p5.ellipse(position.x, position.y, 30, 30)
}

View File

@@ -0,0 +1,81 @@
/**
* @module distance-to-line-segment
*/
/**
* Calculate the square of the distance between a finite line segment and a point. This
* version takes somewhat less convenient parameters than distanceToLineSegment.squared,
* but is more efficient if you are calling it multiple times for the same line segment,
* since you pass in some easily pre-calculated values for the segment.
* @alias module:distance-to-line-segment.squaredWithPrecalc
* @param {number} lx1 - x-coordinate of line segment's first point
* @param {number} ly1 - y-coordinate of line segment's first point
* @param {number} ldx - x-coordinate of the line segment's second point minus lx1
* @param {number} ldy - y-coordinate of the line segment's second point minus ly1
* @param {number} lineLengthSquared - must be ldx\*ldx + ldy\*ldy. Remember, this precalculation
* is for efficiency when calling this multiple times for the same line segment.
* @param {number} px - x coordinate of point
* @param {number} py - y coordinate of point
*/
function distanceSquaredToLineSegment2(lx1:number , ly1:number , ldx:number , ldy:number , lineLengthSquared:number , px:number , py:number ) {
let t; // t===0 at line pt 1 and t ===1 at line pt 2
if (!lineLengthSquared) {
// 0-length line segment. Any t will return same result
t = 0;
}
else {
t = ((px - lx1) * ldx + (py - ly1) * ldy) / lineLengthSquared;
if (t < 0)
t = 0;
else if (t > 1)
t = 1;
}
let lx = lx1 + t * ldx,
ly = ly1 + t * ldy,
dx = px - lx,
dy = py - ly;
return dx*dx + dy*dy;
}
/**
* Calculate the square of the distance between a finite line segment and a point.
* @alias module:distance-to-line-segment.squared
* @param {number} lx1 - x-coordinate of line segment's first point
* @param {number} ly1 - y-coordinate of line segment's first point
* @param {number} lx2 - x-coordinate of the line segment's second point
* @param {number} ly2 - y-coordinate of the line segment's second point
* @param {number} px - x coordinate of point
* @param {number} py - y coordinate of point
*/
function distanceSquaredToLineSegment(lx1:number , ly1:number , lx2:number , ly2:number , px:number , py:number ) {
let ldx = lx2 - lx1,
ldy = ly2 - ly1,
lineLengthSquared = ldx*ldx + ldy*ldy;
return distanceSquaredToLineSegment2(lx1, ly1, ldx, ldy, lineLengthSquared, px, py);
}
/**
* Calculate the distance between a finite line segment and a point. Using distanceToLineSegment.squared can often be more efficient.
* @alias module:distance-to-line-segment
* @param {number} lx1 - x-coordinate of line segment's first point
* @param {number} ly1 - y-coordinate of line segment's first point
* @param {number} lx2 - x-coordinate of the line segment's second point
* @param {number} ly2 - y-coordinate of the line segment's second point
* @param {number} px - x coordinate of point
* @param {number} py - y coordinate of point
*/
function distanceToLineSegment(lx1:number , ly1:number , lx2:number , ly2:number , px:number , py:number )
{
return Math.sqrt(distanceSquaredToLineSegment(lx1, ly1, lx2, ly2, px, py));
}
distanceToLineSegment.squared = distanceSquaredToLineSegment;
distanceToLineSegment.squaredWithPrecalc = distanceSquaredToLineSegment2;
export default distanceToLineSegment;

View File

@@ -7,6 +7,7 @@ import Pickable from "./Pickable";
import Player from "./Player";
import PlayerList from "./PlayerList";
import p5 from "p5";
import Wall from "./Wall";
export default class Game {
@@ -14,12 +15,36 @@ export default class Game {
private _otherPlayers: PlayerList
private items: Pickable[] = []
private images: Map<string, p5.Image> = new Map<string, p5.Image>()
private walls: Wall[] = []
private _bestScore: {
name: string,
score: number
} = {
name: '',
score: 0
}
constructor(_socket: SocketIOClient.Socket) {
this.player = new UserPlayer(_socket,_socket.id, 'Player', {x:0, y:0}, 'white', new Map<number, boolean>(), 100, 10, 10)
this._otherPlayers = new PlayerList()
}
get bestScore() {
return this._bestScore
}
set bestScore(score: {name: string, score: number}) {
this._bestScore = score
}
addWall(wall: Wall) {
this.walls.push(wall)
}
getWalls() {
return this.walls
}
setImages(images: Map<string, p5.Image>) {
this.images = images
}

View File

@@ -4,7 +4,7 @@ export default class Item {
constructor(
private _image: p5.Image,
private _type: "HEAL" | "DAMAGE" | "DEFENCE"
private _type: "HEAL" | "DAMAGE" | "DEFENCE" | "POINTS"
) {
}

View File

@@ -59,7 +59,7 @@ export default class OtherPlayer {
draw(p5: p5, position: Position) {
p5.stroke(0, 0, 0)
p5.strokeWeight(5)
p5.strokeWeight(2)
p5.fill(this.color)
p5.ellipse(position.x, position.y, 80, 80)
p5.textSize(32)

View File

@@ -1,6 +1,8 @@
import { Position } from './types'
import p5 from 'p5'
import Bullet from './Bullet'
import Wall from './Wall'
import { collideRectCircle } from './collide'
export default class Player {
@@ -10,6 +12,11 @@ export default class Player {
private KEY_D = 68
private MOVEMENT_SPEED = 0.8
private PLAYER_SIZE = 80
private BULLET_SIZE = 30
private ITEM_SIZE = 64
private _score = 0
private bullets: Bullet[] = []
@@ -17,7 +24,7 @@ export default class Player {
private _id: string,
private _name: string = 'Player',
private _position: Position = {x: 0, y: 0},
private _color: string = '#ffffff',
private _color: string = '#690000',
private _keysPressed: Map<number, boolean> = new Map<number, boolean>(),
private _health: number = 100,
private _damage: number = 10,
@@ -26,6 +33,14 @@ export default class Player {
this._keysPressed = new Map<number, boolean>()
}
get score() {
return this._score
}
set score(score: number) {
this._score = score
}
get keysPressed() {
return this._keysPressed
}
@@ -116,54 +131,61 @@ export default class Player {
}
}
move(delta: number) {
move(p5: p5, delta: number, walls: Wall[]) {
let direction = {
x: 0,
y: 0
}
if (this.keysPressed.get(this.KEY_A)) {
this.position.x -= this.MOVEMENT_SPEED * delta
direction.x -= 1
}
if (this.keysPressed.get(this.KEY_D)) {
this.position.x += this.MOVEMENT_SPEED * delta
direction.x += 1
}
if (this.keysPressed.get(this.KEY_W)) {
this.position.y -= this.MOVEMENT_SPEED * delta
direction.y -= 1
}
if (this.keysPressed.get(this.KEY_S)) {
this.position.y += this.MOVEMENT_SPEED * delta
direction.y += 1
}
if (this.position.x < -1600) {
this.position.x = -1600
let x = this.position.x + this.MOVEMENT_SPEED * delta * direction.x
let y = this.position.y + this.MOVEMENT_SPEED * delta * direction.y
let newPos = {
x: x,
y: y,
}
for (let wall of walls) {
if (collideRectCircle(p5, wall.position.x, wall.position.y, wall.size.x, wall.size.y, x, this.position.y, this.PLAYER_SIZE)) {
console.log('collision on x')
newPos.x = this.position.x
}
if (collideRectCircle(p5, wall.position.x, wall.position.y, wall.size.x, wall.size.y, this.position.x, y, this.PLAYER_SIZE)) {
console.log('collision on y')
newPos.y = this.position.y
}
}
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
}
this.position = newPos
}
draw(p5: p5, position: Position) {
p5.stroke(0, 0, 0)
p5.strokeWeight(5)
p5.strokeWeight(2)
p5.fill(this.color)
p5.ellipse(position.x, position.y, 80, 80)
p5.ellipse(position.x, position.y, this.PLAYER_SIZE, this.PLAYER_SIZE)
p5.textSize(32)
p5.fill(255, 255, 255)
p5.fill("#690000")
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)
p5.strokeWeight(2)
p5.fill('#690000')
p5.rect(position.x - 50, position.y - 90, 100, 10)
p5.fill('#000000')
p5.rect(position.x - 50, position.y - 90, this.health, 10)
}
addBullet(bullet: Bullet) {

34
client/src/Wall.ts Normal file
View File

@@ -0,0 +1,34 @@
import p5 from "p5";
import { Position } from "./types";
export default class Wall {
constructor(
private _position: Position,
private _size: Position,
) {
}
get position() {
return this._position
}
set position(position: Position) {
this._position = position
}
get size() {
return this._size
}
set size(size: Position) {
this._size = size
}
draw(p5: p5, playerPos: Position) {
p5.fill("#000000")
p5.rect(this.position.x - playerPos.x, this.position.y - playerPos.y, this.size.x, this.size.y)
}
}

View File

@@ -10,6 +10,8 @@ import { Position } from './types'
import Pickable from './Pickable'
import Item from './Item'
import * as uuid from 'uuid'
import Wall from './Wall'
import { collideCircleCircle, collideRectCircle } from './collide'
let socket: SocketIOClient.Socket
let game: Game
@@ -43,6 +45,7 @@ const getDeltaTime = () => {
function onKeyDown(e: any) {
game.getPlayer().keyDown(e.keyCode)
}
function onKeyUp(e: any) {
game.getPlayer().keyUp(e.keyCode)
@@ -126,7 +129,7 @@ function distance(p1: any, p2: any) {
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2))
}
function drawMap(p5: P5) {
function drawMapX(p5: P5) {
for (let tile of mapTiles) {
if (isVisible(game.getPlayer().position, {x: tile.position.x - tile.image.width / 2, y: tile.position.y - tile.image.height / 2})) {
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)
@@ -134,6 +137,17 @@ function drawMap(p5: P5) {
}
}
function drawMap(p5: P5) {
p5.stroke("#000000")
p5.strokeWeight(4)
for (let x = -p5.width; x < p5.width; x+=128) {
p5.line(x - game.getPlayer().position.x % 128, -p5.height, x - game.getPlayer().position.x % 128, p5.height)
}
for (let y = -p5.width; y < p5.height; y+=128) {
p5.line(-p5.width, y - game.getPlayer().position.y % 128, p5.width, y - game.getPlayer().position.y % 128)
}
}
const sketch = (p5: P5) => {
@@ -161,6 +175,18 @@ const sketch = (p5: P5) => {
game = new Game(socket)
game.setImages(images)
// left
game.addWall(new Wall({ x: -3060, y: -3060, }, { x: 20, y: 6120 }))
// top
game.addWall(new Wall({ x: -3060, y: -3060, }, { x: 6120, y: 20 }))
// right
game.addWall(new Wall({ x: 3040, y: -3060, }, { x: 20, y: 6120 }))
// bottom
game.addWall(new Wall({ x: -3060, y: 3040, }, { x: 6120, y: 20 }))
setupSocketEvents(socket, game)
}
@@ -173,18 +199,22 @@ const sketch = (p5: P5) => {
// drawing map background
// drawMap(p5)
drawMap(p5)
p5.strokeWeight(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)
if (distance(game.getPlayer().position, item.position) < PLAYER_SIZE + ITEM_SIZE) {
if (collideRectCircle(p5, item.position.x, item.position.y, ITEM_SIZE, ITEM_SIZE, game.getPlayer().position.x, game.getPlayer().position.y, PLAYER_SIZE)) {
switch(item.item.type) {
case "HEAL":
game.getPlayer().health = 100
socket.emit('item-picked', {id: item.id})
socket.emit('hit-player', {id: game.getPlayer().id, health: game.getPlayer().health})
socket.emit('item-picked', {id: item.id})
break;
case "POINTS":
socket.emit('item-picked', {id: item.id})
break;
// case "DAMAGE":
// game.getPlayer().damage += 2
@@ -211,7 +241,7 @@ const sketch = (p5: P5) => {
})
// move player if in range (guessing where player will be when request from servers comes back)
otherPlayer.move(dt)
otherPlayer.move(p5, dt, game.getWalls())
}
// going through bullets of that player
@@ -229,13 +259,13 @@ const sketch = (p5: P5) => {
bullet.move(dt)
// check if bullet colloides with current player
if (distance(game.getPlayer().position, bullet.position) < BULLET_SIZE + PLAYER_SIZE) {
if (collideCircleCircle(p5, game.getPlayer().position.x, game.getPlayer().position.y, PLAYER_SIZE, bullet.position.x, bullet.position.y, BULLET_SIZE)) {
bullet.timeToLive = -1
}
// check if bullet collides with other player
game.otherPlayers.getPlayers().forEach((otherPlayerCheck) => {
if (distance(otherPlayerCheck.position, bullet.position) < BULLET_SIZE + PLAYER_SIZE) {
if (collideCircleCircle(p5, otherPlayerCheck.position.x, otherPlayerCheck.position.y, PLAYER_SIZE, bullet.position.x, bullet.position.y, BULLET_SIZE)) {
// check if player bullet collides with is not the player who shot the bullet
if (otherPlayerCheck.id !== bullet.shooter.id) {
bullet.timeToLive = -1
@@ -269,25 +299,70 @@ const sketch = (p5: P5) => {
// check if bullet collides with other player
game.otherPlayers.getPlayers().forEach((otherPlayer) => {
if (otherPlayer.id === game.getPlayer().id) return
if (distance(otherPlayer.position, bullet.position) < BULLET_SIZE + PLAYER_SIZE) {
if (collideCircleCircle(p5, otherPlayer.position.x, otherPlayer.position.y, PLAYER_SIZE, bullet.position.x, bullet.position.y, BULLET_SIZE)) {
// register hit to other player
otherPlayer.hit(bullet, game.getPlayer().socket)
}
})
}
for (let wall of game.getWalls()) {
wall.draw(p5, game.getPlayer().position)
}
// removig bullets that has traveled far enough
game.getPlayer().removeExpiredBullets()
// drawing coordinates of the current player
p5.fill('#ffffff')
p5.fill('#690000')
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)
p5.text(Math.floor(game.getPlayer().position.x) + ':' + Math.floor(game.getPlayer().position.y), -p5.width/2 + 30, -p5.height/2 + 30)
p5.fill('#690000')
p5.stroke('#000000')
p5.textAlign(p5.RIGHT, p5.TOP)
p5.text('Players: ' + (+game.otherPlayers.getPlayers().size + 1), p5.width/2 - 30, -p5.height/2 + 30)
p5.fill('#690000')
p5.stroke('#000000')
p5.textAlign(p5.RIGHT, p5.BOTTOM)
let scores = new Map<string, number>()
game.otherPlayers.getPlayers().forEach((player) => {
scores.set(player.id, player.score)
})
scores.set(game.getPlayer().id, game.getPlayer().score)
scores[Symbol.iterator] = function* () {
yield* [...this.entries()].sort((a, b) => b[1] - a[1]);
}
let text = 'All time best: ' + game.bestScore.name + ': ' + game.bestScore.score + '\n\n'
for (let [id, score] of scores) {
let player = game.otherPlayers.getPlayer(id)
if (!player) {
if (game.getPlayer().id === id) {
player = game.getPlayer()
}
}
if (player) {
text += '\n' + player.name + ': ' + score
}
}
text += `\n---------\nYour score: ${game.getPlayer().score}`;
p5.text(text, p5.width/2 - 830, p5.height/2 - 830, 800, 800)
// moving player depending on keys pressed
let previousePosition = {...game.getPlayer().position}
game.getPlayer().move(dt)
game.getPlayer().move(p5, dt, game.getWalls())
let newPosition = {...game.getPlayer().position}
if (previousePosition.x !== newPosition.x || previousePosition.y !== newPosition.y) {
game.getPlayer().socket.emit('player-moved', {position: newPosition})

520
client/src/collide.ts Normal file
View File

@@ -0,0 +1,520 @@
/*
Repo: https://github.com/bmoren/p5.collide2D/
Created by http://benmoren.com
Some functions and code modified version from http://www.jeffreythompson.org/collision-detection
Version v0.7.3 | June 22, 2020
CC BY-NC-SA 4.0
File edited to fit my needs and project
*/
import p5 from 'p5'
// const collideRectRect = function (x, y, w, h, x2, y2, w2, h2) {
// //2d
// //add in a thing to detect rectMode CENTER
// if (x + w >= x2 && // r1 right edge past r2 left
// x <= x2 + w2 && // r1 left edge past r2 right
// y + h >= y2 && // r1 top edge past r2 bottom
// y <= y2 + h2) { // r1 bottom edge past r2 top
// return true;
// }
// return false;
// };
// // p5.vector version of collideRectRect
// p5.prototype.collideRectRectVector = function(p1, sz, p2, sz2){
// return p5.prototype.collideRectRect(p1.x, p1.y, sz.x, sz.y, p2.x, p2.y, sz2.x,sz2.y)
// }
const collideRectCircle = function (p5: p5, rx: number, ry: number, rw: number, rh: number, cx: number, cy: number, diameter: number) {
//2d
// temporary variables to set edges for testing
var testX = cx;
var testY = cy;
// which edge is closest?
if (cx < rx){ testX = rx // left edge
}else if (cx > rx+rw){ testX = rx+rw } // right edge
if (cy < ry){ testY = ry // top edge
}else if (cy > ry+rh){ testY = ry+rh } // bottom edge
// // get distance from closest edges
var distance = p5.dist(cx,cy,testX,testY)
// if the distance is less than the radius, collision!
if (distance <= diameter/2) {
return true;
}
return false;
};
// // p5.vector version of collideRectCircle
// p5.prototype.collideRectCircleVector = function(r, sz, c, diameter){
// return p5.prototype.collideRectCircle(r.x,r.y, sz.x,sz.y, c.x,c.y, diameter)
// }
const collideCircleCircle = function (p5: p5, x: number, y: number, d: number, x2: number, y2: number, d2: number) {
//2d
if( p5.dist(x,y,x2,y2) <= (d/2)+(d2/2) ){
return true;
}
return false;
};
// p5.vector version of collideCircleCircle
// p5.prototype.collideCircleCircleVector = function(p1,d, p2, d2){
// return p5.prototype.collideCircleCircle(p1.x,p1.y, d, p2.x,p2.y, d2)
// }
// p5.prototype.collidePointCircle = function (x, y, cx, cy, d) {
// //2d
// if( this.dist(x,y,cx,cy) <= d/2 ){
// return true;
// }
// return false;
// };
// // p5.vector version of collidePointCircle
// p5.prototype.collidePointCircleVector = function(p, c, d){
// return p5.prototype.collidePointCircle(p.x,p.y,c.x,c.y, d)
// }
// p5.prototype.collidePointEllipse = function (x, y, cx, cy, dx, dy) {
// //2d
// var rx = dx/2, ry = dy/2;
// // Discarding the points outside the bounding box
// if (x > cx + rx || x < cx - rx ||y > cy + ry || y < cy - ry) {
// return false;
// }
// // Compare the point to its equivalent on the ellipse
// var xx = x - cx, yy = y - cy;
// var eyy = ry * this.sqrt(this.abs(rx * rx - xx * xx)) / rx;
// return yy <= eyy && yy >= -eyy;
// };
// // p5.vector version of collidePointEllipse
// p5.prototype.collidePointEllipseVector = function(p, c, d){
// return p5.prototype.collidePointEllipse(p.x,p.y,c.x,c.y,d.x,d.y);
// }
// p5.prototype.collidePointRect = function (pointX, pointY, x, y, xW, yW) {
// //2d
// if (pointX >= x && // right of the left edge AND
// pointX <= x + xW && // left of the right edge AND
// pointY >= y && // below the top AND
// pointY <= y + yW) { // above the bottom
// return true;
// }
// return false;
// };
// // p5.vector version of collidePointRect
// p5.prototype.collidePointRectVector = function(point, p1, sz){
// return p5.prototype.collidePointRect(point.x, point.y, p1.x, p1.y, sz.x, sz.y);
// }
// p5.prototype.collidePointLine = function(px,py,x1,y1,x2,y2, buffer){
// // get distance from the point to the two ends of the line
// var d1 = this.dist(px,py, x1,y1);
// var d2 = this.dist(px,py, x2,y2);
// // get the length of the line
// var lineLen = this.dist(x1,y1, x2,y2);
// // since floats are so minutely accurate, add a little buffer zone that will give collision
// if (buffer === undefined){ buffer = 0.1; } // higher # = less accurate
// // if the two distances are equal to the line's length, the point is on the line!
// // note we use the buffer here to give a range, rather than one #
// if (d1+d2 >= lineLen-buffer && d1+d2 <= lineLen+buffer) {
// return true;
// }
// return false;
// }
// // p5.vector version of collidePointLine
// p5.prototype.collidePointLineVector = function(point,p1,p2, buffer){
// return p5.prototype.collidePointLine(point.x,point.y, p1.x,p1.y, p2.x,p2.y, buffer);
// }
// p5.prototype.collideLineCircle = function( x1, y1, x2, y2, cx, cy, diameter) {
// // is either end INSIDE the circle?
// // if so, return true immediately
// var inside1 = this.collidePointCircle(x1,y1, cx,cy,diameter);
// var inside2 = this.collidePointCircle(x2,y2, cx,cy,diameter);
// if (inside1 || inside2) return true;
// // get length of the line
// var distX = x1 - x2;
// var distY = y1 - y2;
// var len = this.sqrt( (distX*distX) + (distY*distY) );
// // get dot product of the line and circle
// var dot = ( ((cx-x1)*(x2-x1)) + ((cy-y1)*(y2-y1)) ) / this.pow(len,2);
// // find the closest point on the line
// var closestX = x1 + (dot * (x2-x1));
// var closestY = y1 + (dot * (y2-y1));
// // is this point actually on the line segment?
// // if so keep going, but if not, return false
// var onSegment = this.collidePointLine(closestX,closestY,x1,y1,x2,y2);
// if (!onSegment) return false;
// // draw a debug circle at the closest point on the line
// if(this._collideDebug){
// this.ellipse(closestX, closestY,10,10);
// }
// // get distance to closest point
// distX = closestX - cx;
// distY = closestY - cy;
// var distance = this.sqrt( (distX*distX) + (distY*distY) );
// if (distance <= diameter/2) {
// return true;
// }
// return false;
// }
// // p5.vector version of collideLineCircle
// p5.prototype.collideLineCircleVector = function( p1, p2, c, diameter){
// return p5.prototype.collideLineCircle( p1.x, p1.y, p2.x, p2.y, c.x, c.y, diameter);
// }
// p5.prototype.collideLineLine = function(x1, y1, x2, y2, x3, y3, x4, y4,calcIntersection) {
// var intersection;
// // calculate the distance to intersection point
// var uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
// var uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
// // if uA and uB are between 0-1, lines are colliding
// if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
// if(this._collideDebug || calcIntersection){
// // calc the point where the lines meet
// var intersectionX = x1 + (uA * (x2-x1));
// var intersectionY = y1 + (uA * (y2-y1));
// }
// if(this._collideDebug){
// this.ellipse(intersectionX,intersectionY,10,10);
// }
// if(calcIntersection){
// intersection = {
// "x":intersectionX,
// "y":intersectionY
// }
// return intersection;
// }else{
// return true;
// }
// }
// if(calcIntersection){
// intersection = {
// "x":false,
// "y":false
// }
// return intersection;
// }
// return false;
// }
// // p5.vector version of collideLineLine
// p5.prototype.collideLineLineVector = function(p1, p2, p3, p4, calcIntersection){
// return p5.prototype.collideLineLine(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, calcIntersection);
// }
// p5.prototype.collideLineRect = function(x1, y1, x2, y2, rx, ry, rw, rh, calcIntersection) {
// // check if the line has hit any of the rectangle's sides. uses the collideLineLine function above
// var left, right, top, bottom, intersection;
// if(calcIntersection){
// left = this.collideLineLine(x1,y1,x2,y2, rx,ry,rx, ry+rh,true);
// right = this.collideLineLine(x1,y1,x2,y2, rx+rw,ry, rx+rw,ry+rh,true);
// top = this.collideLineLine(x1,y1,x2,y2, rx,ry, rx+rw,ry,true);
// bottom = this.collideLineLine(x1,y1,x2,y2, rx,ry+rh, rx+rw,ry+rh,true);
// intersection = {
// "left" : left,
// "right" : right,
// "top" : top,
// "bottom" : bottom
// }
// }else{
// //return booleans
// left = this.collideLineLine(x1,y1,x2,y2, rx,ry,rx, ry+rh);
// right = this.collideLineLine(x1,y1,x2,y2, rx+rw,ry, rx+rw,ry+rh);
// top = this.collideLineLine(x1,y1,x2,y2, rx,ry, rx+rw,ry);
// bottom = this.collideLineLine(x1,y1,x2,y2, rx,ry+rh, rx+rw,ry+rh);
// }
// // if ANY of the above are true, the line has hit the rectangle
// if (left || right || top || bottom) {
// if(calcIntersection){
// return intersection;
// }
// return true;
// }
// return false;
// }
// // p5.vector version of collideLineRect
// p5.prototype.collideLineRectVector = function(p1, p2, r, rsz, calcIntersection){
// return p5.prototype.collideLineRect(p1.x, p1.y, p2.x, p2.y, r.x, r.y, rsz.x, rsz.y, calcIntersection);
// }
// p5.prototype.collidePointPoly = function(px, py, vertices) {
// var collision = false;
// // go through each of the vertices, plus the next vertex in the list
// var next = 0;
// for (var current=0; current<vertices.length; current++) {
// // get next vertex in list if we've hit the end, wrap around to 0
// next = current+1;
// if (next === vertices.length) next = 0;
// // get the PVectors at our current position this makes our if statement a little cleaner
// var vc = vertices[current]; // c for "current"
// var vn = vertices[next]; // n for "next"
// // compare position, flip 'collision' variable back and forth
// if (((vc.y >= py && vn.y < py) || (vc.y < py && vn.y >= py)) &&
// (px < (vn.x-vc.x)*(py-vc.y) / (vn.y-vc.y)+vc.x)) {
// collision = !collision;
// }
// }
// return collision;
// }
// // p5.vector version of collidePointPoly
// p5.prototype.collidePointPolyVector = function(p1, vertices){
// return p5.prototype.collidePointPoly(p1.x, p1.y, vertices);
// }
// // POLYGON/CIRCLE
// p5.prototype.collideCirclePoly = function(cx, cy, diameter, vertices, interior) {
// if (interior === undefined){
// interior = false;
// }
// // go through each of the vertices, plus the next vertex in the list
// var next = 0;
// for (var current=0; current<vertices.length; current++) {
// // get next vertex in list if we've hit the end, wrap around to 0
// next = current+1;
// if (next === vertices.length) next = 0;
// // get the PVectors at our current position this makes our if statement a little cleaner
// var vc = vertices[current]; // c for "current"
// var vn = vertices[next]; // n for "next"
// // check for collision between the circle and a line formed between the two vertices
// var collision = this.collideLineCircle(vc.x,vc.y, vn.x,vn.y, cx,cy,diameter);
// if (collision) return true;
// }
// // test if the center of the circle is inside the polygon
// if(interior === true){
// var centerInside = this.collidePointPoly(cx,cy, vertices);
// if (centerInside) return true;
// }
// // otherwise, after all that, return false
// return false;
// }
// // p5.vector version of collideCirclePoly
// p5.prototype.collideCirclePolyVector = function(c, diameter, vertices, interior){
// return p5.prototype.collideCirclePoly(c.x, c.y, diameter, vertices, interior);
// }
// p5.prototype.collideRectPoly = function( rx, ry, rw, rh, vertices, interior) {
// if (interior == undefined){
// interior = false;
// }
// // go through each of the vertices, plus the next vertex in the list
// var next = 0;
// for (var current=0; current<vertices.length; current++) {
// // get next vertex in list if we've hit the end, wrap around to 0
// next = current+1;
// if (next === vertices.length) next = 0;
// // get the PVectors at our current position this makes our if statement a little cleaner
// var vc = vertices[current]; // c for "current"
// var vn = vertices[next]; // n for "next"
// // check against all four sides of the rectangle
// var collision = this.collideLineRect(vc.x,vc.y,vn.x,vn.y, rx,ry,rw,rh);
// if (collision) return true;
// // optional: test if the rectangle is INSIDE the polygon note that this iterates all sides of the polygon again, so only use this if you need to
// if(interior === true){
// var inside = this.collidePointPoly(rx,ry, vertices);
// if (inside) return true;
// }
// }
// return false;
// }
// // p5.vector version of collideRectPoly
// p5.prototype.collideRectPolyVector = function(r, rsz, vertices, interior){
// return p5.prototype.collideRectPoly(r.x, r.y, rsz.x, rsz.y, vertices, interior);
// }
// p5.prototype.collideLinePoly = function(x1, y1, x2, y2, vertices) {
// // go through each of the vertices, plus the next vertex in the list
// var next = 0;
// for (var current=0; current<vertices.length; current++) {
// // get next vertex in list if we've hit the end, wrap around to 0
// next = current+1;
// if (next === vertices.length) next = 0;
// // get the PVectors at our current position extract X/Y coordinates from each
// var x3 = vertices[current].x;
// var y3 = vertices[current].y;
// var x4 = vertices[next].x;
// var y4 = vertices[next].y;
// // do a Line/Line comparison if true, return 'true' immediately and stop testing (faster)
// var hit = this.collideLineLine(x1, y1, x2, y2, x3, y3, x4, y4);
// if (hit) {
// return true;
// }
// }
// // never got a hit
// return false;
// }
// // p5.vector version of collideLinePoly
// p5.prototype.collideLinePolyVector = function(p1, p2, vertice){
// return p5.prototype.collideLinePoly(p1.x, p1.y, p2.x, p2.y, vertice);
// }
// p5.prototype.collidePolyPoly = function(p1, p2, interior) {
// if (interior === undefined){
// interior = false;
// }
// // go through each of the vertices, plus the next vertex in the list
// var next = 0;
// for (var current=0; current<p1.length; current++) {
// // get next vertex in list, if we've hit the end, wrap around to 0
// next = current+1;
// if (next === p1.length) next = 0;
// // get the PVectors at our current position this makes our if statement a little cleaner
// var vc = p1[current]; // c for "current"
// var vn = p1[next]; // n for "next"
// //use these two points (a line) to compare to the other polygon's vertices using polyLine()
// var collision = this.collideLinePoly(vc.x,vc.y,vn.x,vn.y,p2);
// if (collision) return true;
// //check if the either polygon is INSIDE the other
// if(interior === true){
// collision = this.collidePointPoly(p2[0].x, p2[0].y, p1);
// if (collision) return true;
// collision = this.collidePointPoly(p1[0].x, p1[0].y, p2);
// if (collision) return true;
// }
// }
// return false;
// }
// p5.prototype.collidePolyPolyVector = function(p1, p2, interior) {
// return p5.prototype.collidePolyPoly(p1, p2, interior);
// }
// p5.prototype.collidePointTriangle = function(px, py, x1, y1, x2, y2, x3, y3) {
// // get the area of the triangle
// var areaOrig = this.abs( (x2-x1)*(y3-y1) - (x3-x1)*(y2-y1) );
// // get the area of 3 triangles made between the point and the corners of the triangle
// var area1 = this.abs( (x1-px)*(y2-py) - (x2-px)*(y1-py) );
// var area2 = this.abs( (x2-px)*(y3-py) - (x3-px)*(y2-py) );
// var area3 = this.abs( (x3-px)*(y1-py) - (x1-px)*(y3-py) );
// // if the sum of the three areas equals the original, we're inside the triangle!
// if (area1 + area2 + area3 === areaOrig) {
// return true;
// }
// return false;
// }
// // p5.vector version of collidePointTriangle
// p5.prototype.collidePointTriangleVector = function(p, p1, p2, p3){
// return p5.prototype.collidePointTriangle(p.x, p.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
// }
// p5.prototype.collidePointPoint = function (x,y,x2,y2, buffer) {
// if(buffer === undefined){
// buffer = 0;
// }
// if(this.dist(x,y,x2,y2) <= buffer){
// return true;
// }
// return false;
// };
// // p5.vector version of collidePointPoint
// p5.prototype.collidePointPointVector = function(p1, p2, buffer){
// return p5.prototype.collidePointPoint(p1.x,p1.y,p2.x,p2.y, buffer);
// }
// p5.prototype.collidePointArc = function(px, py, ax, ay, arcRadius, arcHeading, arcAngle, buffer) {
// if (buffer === undefined) {
// buffer = 0;
// }
// // point
// var point = this.createVector(px, py);
// // arc center point
// var arcPos = this.createVector(ax, ay);
// // arc radius vector
// var radius = this.createVector(arcRadius, 0).rotate(arcHeading);
// var pointToArc = point.copy().sub(arcPos);
// if (point.dist(arcPos) <= (arcRadius + buffer)) {
// var dot = radius.dot(pointToArc);
// var angle = radius.angleBetween(pointToArc);
// if (dot > 0 && angle <= arcAngle / 2 && angle >= -arcAngle / 2) {
// return true;
// }
// }
// return false;
// }
// // p5.vector version of collidePointArc
// p5.prototype.collidePointArcVector = function(p1, a, arcRadius, arcHeading, arcAngle, buffer){
// return p5.prototype.collidePointArc(p1.x, p1.y, a.x, a.y, arcRadius, arcHeading, arcAngle, buffer);
// }
export {
collideCircleCircle,
collideRectCircle
}

View File

@@ -12,6 +12,7 @@ export default function prealoadResources(p5: P5): {
// images.set('powerUp', p5.loadImage('images/PowerUp.png'))
// images.set('shield', p5.loadImage('images/Shield.png'))
images.set('healthPack', p5.loadImage('images/HealthPack.png'))
images.set('Points', p5.loadImage('images/Points.png'))
fonts.set('Ubuntu', p5.loadFont('fonts/Ubuntu/Ubuntu-Regular.ttf'))

View File

@@ -1,4 +1,5 @@
import SocketIOClient from 'socket.io-client'
import { stringify } from 'uuid'
import Bullet from './Bullet'
import { getCookie } from './Cookie'
import Game from './Game'
@@ -12,7 +13,7 @@ import { Position } from './types'
export default function setupSocketEvents(socket: SocketIOClient.Socket, game: Game) {
socket.on('greetings', () => {
socket.emit('greetings', {name: getCookie('player-name')})
socket.emit('greetings', {name: getCookie('player-name').substr(0, 32)})
})
socket.on('your-info', function (playerData: PlayerDescription) {
@@ -87,14 +88,31 @@ export default function setupSocketEvents(socket: SocketIOClient.Socket, game: G
window.location.href = '/ded';
})
socket.on('new-item', (data: {id: string, position: Position, item: {image: 'healthPack', type: "HEAL"}}) => {
socket.on('new-item', (data: {id: string, position: Position, item: {image: 'healthPack' | 'Points', type: "HEAL" | "POINTS"}}) => {
let image = game.getImages().get(data.item.image)
if (image) {
game.addItem(new Pickable(data.id, data.position, new Item(image, data.item.type)))
}
})
socket.on('item-picked', (data: {id: string}) => {
socket.on('update-score', (data: {id: string, score: number}) => {
let oPlayer = game.otherPlayers.getPlayer(data.id)
if (oPlayer) {
oPlayer.score = data.score
}
if (game.getPlayer().id === data.id) {
game.getPlayer().score = data.score
}
})
socket.on('best-player', (data: {name: string, score: number}) => {
game.bestScore = {
name: data.name,
score: data.score
}
})
socket.on('item-picked-resolve', (data: {id: string}) => {
game.removeItemById(data.id)
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

View File

@@ -1,66 +0,0 @@
# Welcome to p5.js
You have downloaded the complete p5.js library ZIP file, yay!
# Contents of the p5 folder
* p5.js file
* p5.min.js file
* addons folder
* p5.sound.js
* p5.sound.min.js
* empty-example folder
* index.html
* p5.js
* p5.sound.js
* sketch.js
## p5.js
This file stores the complete p5.js library. It is easy to read by humans, so feel free to open it and explore its contents. It also has a friendly error system, which helps new programmers with common user errors.
## p5.min.js
This file is a minified version of the p5.js file. It is a lighter version, with the same functionalities, but smaller file size. This minified version is harder to read for humans, and does not include the friendly error system.
## addons folder
The addons folder includes additional p5.js related libraries, in both original versions and minified versions.
### p5.sound.js, p5.sound.min.js
p5.sound extends p5.js with Web Audio functionality including audio input, playback, analysis, and synthesis.
## empty-example folder
This is an empty example of a website. The folder includes the file for the website, index.html, the p5.js library, other related p5.js libraries, and a template starting point for your p5.js sketch, called sketch.js.
### index.html
index.html is a template for an HTML file. This index.html first imports the libraries included in the folder (p5.js, p5.sound.js) then loads and executes the file sketch.js which is where you can write your own code.
### sketch.js
The sketch.js is a template for the p5.js sketch, with the functions setup() and draw() that you can complete.
## README.txt
This README file formatted with Markdown :)
# What's next?
If you need more information to help get you started, please refer to our website:
https://p5js.org/get-started/ and https://p5js.org/learn/
An online reference to the p5.js library is available here:
https://p5js.org/reference/
In order to run your website (including the empty-example), you need to enable a local server, please see this tutorial in our wiki:
https://github.com/processing/p5.js/wiki/Local-server
p5.js is a community and p5.js is built by contributions. If you want to learn more about us, visit:
https://p5js.org/community/
# License
The p5.js library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 2.1.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -9,6 +9,7 @@
margin: 0;
padding: 0;
box-sizing: border-box;
color: #850000;
}
main {
background: #000000;
@@ -20,7 +21,6 @@
}
div {
display: block;
color: #850000;
font-size: 8rem;
}
</style>

View File

@@ -29,7 +29,7 @@
}
div {
color: #7F0000;
color: #690000;
text-align: center;
}
@@ -49,9 +49,9 @@
font-size: 20pt;
}
input, button {
border: 1px solid #7F0000;
border: 1px solid #690000;
background: transparent;
color: #7F0000;
color: #690000;
outline: transparent;
}
@@ -63,6 +63,14 @@
a {
text-decoration: none;
}
span.notice {
color: #690000;
position: fixed;
display: block;
bottom: 24px;
left: 24px;
}
</style>
</head>
<body>
@@ -76,6 +84,7 @@
</label>
</div>
</main>
<span class="notice">* This game is being developed straigt onto this website, so random restarts might occur during gameplay!</div>
<script>
function updateName(input) {
setCookie('player-name', input.value || 'Player', 30)

1
server/score.json Normal file
View File

@@ -0,0 +1 @@
{"RDarius":4,"RDarius#6":5,"vincentas":3}

View File

@@ -1,8 +1,8 @@
export default class Item {
constructor(
private _image: "healthPack",
private _type: "HEAL" | "DAMAGE" | "DEFENCE"
private _image: "healthPack" | "Points",
private _type: "HEAL" | "DAMAGE" | "DEFENCE" | "POINTS"
) {
}

View File

@@ -10,6 +10,7 @@ export default class Player {
private damage: number
private defence: number
private keysPressed: Map<number, boolean>
private score: number = 0
constructor(private _socket: socketIO.Socket) {
this.name = 'Player#' + Math.floor(Math.random() * 10000)
@@ -17,13 +18,21 @@ export default class Player {
x: Math.random()*1000 - 500,
y: Math.random()*1000 - 500,
}
this.color = '#' + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16)
this.color = '#690000'// + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16) + (Math.floor(Math.random() * 256)).toString(16)
this.health = Math.floor(Math.random() * 50) + 50
this.damage = 10
this.defence = 0
this.keysPressed = new Map<number, boolean>()
}
addScore() {
this.score++
}
getScore() {
return this.score
}
get socket() {
return this._socket
}

View File

@@ -10,15 +10,27 @@ import { Position } from './types'
import Pickable from './Pickable'
import Item from './Item'
import * as uuid from 'uuid'
import fs from 'fs'
const minx = -3000
const maxx = 3000
const miny = -3000
const maxy = 3000
const app = express()
const server = new http.Server(app)
const io = new socketIO.Server(server)
const players = new Players()
const items: Pickable[] = []
let items: Pickable[] = []
const playerList = new PlayerList()
let scores = JSON.parse(fs.readFileSync(__dirname + '/../score.json').toString())
app.use(cors())
app.use(express.static(path.join(__dirname, '/../../client/static/assets')))
@@ -40,6 +52,22 @@ server.listen(8089, function() {
console.log('running on port 8089');
});
function makePointsItem() {
let item = new Item('Points', "POINTS")
let pickable = new Pickable(
uuid.v4(),
{
x: Math.floor(Math.random() * (Math.abs(minx) + maxx) + minx),
y: Math.floor(Math.random() * (Math.abs(miny) + maxy) + miny),
},
item
)
items.push(pickable)
io.emit('new-item', {id: pickable.id, position: pickable.position, item: {image: pickable.item.image, type: pickable.item.type}})
}
makePointsItem()
io.on('connection', function(socket: socketIO.Socket) {
console.log(socket.id, 'connected');
@@ -52,6 +80,21 @@ io.on('connection', function(socket: socketIO.Socket) {
socket.emit('your-info', player.getPlayerDescription())
io.emit('new-player-joined', player.getPlayerDescription())
let best = {
name: '',
score: 0
}
for (let name in scores) {
if (scores[name] > best.score) {
best.name = name
best.score = scores[name]
}
}
socket.emit('best-player', best)
})
socket.on('get-other-players', () => {
@@ -99,7 +142,46 @@ io.on('connection', function(socket: socketIO.Socket) {
})
socket.on('item-picked', (data: {id: string}) => {
socket.broadcast.emit('item-picked', {id: data.id})
console.log('item picked')
let player = playerList.getPlayer(socket.id)
if (player) {
console.log('player found')
for (let item of items) {
if (item.id === data.id && item.item.type === "POINTS") {
console.log('item points')
player.addScore()
if (scores[player.getName()] && scores[player.getName()] < player.getScore()) {
console.log('update score')
scores[player.getName()] = player.getScore()
fs.writeFileSync(__dirname + '/../score.json', JSON.stringify(scores))
} else {
console.log('new score')
scores[player.getName()] = player.getScore()
fs.writeFileSync(__dirname + '/../score.json', JSON.stringify(scores))
}
let best = {
name: '',
score: 0
}
for (let name in scores) {
if (scores[name] > best.score) {
best.name = name
best.score = scores[name]
}
}
io.emit('best-player', best)
io.emit('update-score', {id: player.socket.id, score: player.getScore()})
makePointsItem()
break;
}
}
}
items = items.filter((item) => {
return item.id !== data.id
})
socket.broadcast.emit('item-picked-resolve', {id: data.id})
})
@@ -167,12 +249,7 @@ io.on('connection', function(socket: socketIO.Socket) {
setInterval(() => {
const minx = -1600
const maxx = 1500
const miny = -2000
const maxy = 1900
if (items.length < 20) {
if (items.length < 21) {
let item = new Item('healthPack', "HEAL")
let pickable = new Pickable(
uuid.v4(),