Skip to content
Snippets Groups Projects
Commit 5de7867e authored by Fredrik Fonn Hansen's avatar Fredrik Fonn Hansen :8ball:
Browse files

Resolve "backend terrain should only send 15 y-coordinates"

parent b7d36c03
No related branches found
No related tags found
1 merge request!71Resolve "backend terrain should only send 15 y-coordinates"
...@@ -36,7 +36,7 @@ Prettier: ...@@ -36,7 +36,7 @@ Prettier:
- npx prettier --check . - npx prettier --check .
retry: 1 retry: 1
rules: rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"' - if: '($CI_PIPELINE_SOURCE == "push" || $CI_COMMIT_BRANCH == "main") && $CI_PIPELINE_SOURCE != "schedule"'
Typescript-compile: Typescript-compile:
image: node:16.10.0 image: node:16.10.0
...@@ -47,7 +47,7 @@ Typescript-compile: ...@@ -47,7 +47,7 @@ Typescript-compile:
- yarn --cache-folder ../.yarn - yarn --cache-folder ../.yarn
- yarn tsc - yarn tsc
rules: rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"' - if: '($CI_PIPELINE_SOURCE == "push" || $CI_COMMIT_BRANCH == "main") && $CI_PIPELINE_SOURCE != "schedule"'
API-test: API-test:
image: cypress/base:14.17.0 image: cypress/base:14.17.0
...@@ -72,8 +72,7 @@ API-test: ...@@ -72,8 +72,7 @@ API-test:
- cypress/videos/*.mp4 - cypress/videos/*.mp4
expire_in: 1 week # Set the artifact expiration time according to your needs expire_in: 1 week # Set the artifact expiration time according to your needs
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE != "schedule"'
- if: '$CI_PIPELINE_SOURCE == "schedule" && $RUN_VM_HEARTBEAT == "true"'
Gradle-build: Gradle-build:
...@@ -93,7 +92,7 @@ Gradle-build: ...@@ -93,7 +92,7 @@ Gradle-build:
- ./gradlew build --refresh-dependencies - ./gradlew build --refresh-dependencies
- gradle build - gradle build
rules: rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"' - if: '($CI_PIPELINE_SOURCE == "push" || $CI_COMMIT_BRANCH == "main") && $CI_PIPELINE_SOURCE != "schedule"'
VM Deploy: VM Deploy:
image: node:16.10.0 image: node:16.10.0
...@@ -111,8 +110,7 @@ VM Deploy: ...@@ -111,8 +110,7 @@ VM Deploy:
script: script:
- ssh -v -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no ubuntu@10.212.26.72 -p 22 "bash /home/git/tdt4240-tank-wars/backend/vm.sh </dev/null >/dev/null 2>&1" - ssh -v -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no ubuntu@10.212.26.72 -p 22 "bash /home/git/tdt4240-tank-wars/backend/vm.sh </dev/null >/dev/null 2>&1"
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE != "schedule"'
- if: '$CI_PIPELINE_SOURCE == "schedule" && $RUN_VM_HEARTBEAT == "true"'
VM Heartbeat: VM Heartbeat:
stage: deploy stage: deploy
...@@ -134,5 +132,4 @@ VM Heartbeat: ...@@ -134,5 +132,4 @@ VM Heartbeat:
echo "Server did not respond with 200 OK after 3 minutes" echo "Server did not respond with 200 OK after 3 minutes"
exit 1 exit 1
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main" || $CI_PIPELINE_SOURCE == "schedule"'
- if: '$CI_PIPELINE_SOURCE == "schedule" && $RUN_VM_HEARTBEAT == "true"' \ No newline at end of file
\ No newline at end of file
...@@ -12,7 +12,7 @@ describe('Game Test', () => { ...@@ -12,7 +12,7 @@ describe('Game Test', () => {
cy.genericRequest('GET', `/game/${lobby}`, 200, ''); cy.genericRequest('GET', `/game/${lobby}`, 200, '');
}); });
it('Can get currentTurn', () => { it('Can get game-id from a lobby', () => {
cy.request({ cy.request({
method: 'GET', method: 'GET',
url: `${Cypress.config('baseUrl')}/game/${lobby}`, url: `${Cypress.config('baseUrl')}/game/${lobby}`,
......
import slopePreview from './console';
const { createNoise2D } = require('simplex-noise'); const { createNoise2D } = require('simplex-noise');
function generateYValues(maxY: number, numValues: number): number[] { /**
* Creates a more realistic terrain by generating a random number of points and interpolating between them.
* @param maxY The max height of the terrain
* @param numValues The number of points to generate
* @returns An array of y-values
*/
export default function generateYValues(maxY: number, numValues: number): number[] {
const yValues: number[] = []; const yValues: number[] = [];
const noiseScale = 0.0025; const noiseScale = 0.0025;
...@@ -13,8 +21,25 @@ function generateYValues(maxY: number, numValues: number): number[] { ...@@ -13,8 +21,25 @@ function generateYValues(maxY: number, numValues: number): number[] {
const y = maxY * (0.5 + 0.5 * noiseValue); // Scale and shift the noise value to fit in the [0, maxY] range const y = maxY * (0.5 + 0.5 * noiseValue); // Scale and shift the noise value to fit in the [0, maxY] range
yValues.push(y); yValues.push(y);
} }
// slopePreview(yValues, maxY, 40, 20);
return yValues; return yValues;
} }
export default generateYValues; /**
* Generates an array of random numbers.
* @param n number of points to generate
* @param min minumum value
* @param max maximum value
* @returns array of random numbers
*/
export function generateRandomNumbers(n: number, min: number, max: number): number[] {
const randomNumbers: number[] = [];
for (let i = 0; i < n; i++) {
const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
randomNumbers.push(randomNumber);
}
return randomNumbers;
}
import { IGame } from '../interfaces/IGame'; import { IGame } from '../interfaces/IGame';
import { log } from './console'; import { log } from './console';
// check if projectile hit a tank /**
* Legacy code: This function is not used in the current version of the game.
* It was used in the previous version of the game to check if a projectile hit a user.
* It is kept here for reference.
* Now this functionality is handled by the frontend/client.
* @param gameState
* @returns boolean
*/
export function checkProjectileHit(gameState: any): boolean { export function checkProjectileHit(gameState: any): boolean {
const projectileSpeed = 10; // TODO this should be included in the gameState const projectileSpeed = 10; // TODO this should be included in the gameState
const gravity = 9.81; const gravity = 9.81;
...@@ -10,7 +17,7 @@ export function checkProjectileHit(gameState: any): boolean { ...@@ -10,7 +17,7 @@ export function checkProjectileHit(gameState: any): boolean {
// get the current user // get the current user
const currentUser = gameState.users[gameState.currentTurn].user; const currentUser = gameState.users[gameState.currentTurn].user;
const currentUserStats = gameState.users[gameState.currentTurn].stats; const currentUserStats = gameState.users[gameState.currentTurn].stats;
const currentUserPosition = gameState.users[gameState.currentTurn].stats.position; const currentUserPosition = gameState.users[gameState.currentTurn].stats?.position;
const turretAngle = currentUserStats.turretAngle; const turretAngle = currentUserStats.turretAngle;
const turretAngleInRadians = (turretAngle * Math.PI) / 180; const turretAngleInRadians = (turretAngle * Math.PI) / 180;
......
import { IGame } from '../interfaces/IGame';
import { log } from './console';
export default function validate(oldGameState: IGame, newGameState: IGame): boolean {
// compare the current game state with the new game state
if (oldGameState.gameId !== newGameState.gameId) {
log('Game ID mismatch');
return false;
}
if (oldGameState.gameStatus !== newGameState.gameStatus) {
log('Game status mismatch');
return false;
}
if (oldGameState.users.length !== newGameState.users.length) {
log('User length mismatch');
return false;
}
return true;
}
export interface ITerrain { export interface ITerrain {
yValues: number[]; yValues: number[];
xPoints: number; minValue: number;
maxY: number; maxValue: number;
n: number; // number of points to generate
generate(): number[]; generate(): number[];
getYValues(): number[]; getYValues(): number[];
} }
// class for handling game logic // class for handling game logic
import { User } from '../../types/User'; import { User } from '../../types/User';
import { checkProjectileHit } from '../functions/checkProjectileHit';
import { log } from '../functions/console'; import { log } from '../functions/console';
import validateGameState from '../functions/validateGameState';
import { IGame } from '../interfaces/IGame'; import { IGame } from '../interfaces/IGame';
import { ILobby } from '../interfaces/ILobby'; import { ILobby } from '../interfaces/ILobby';
import { IStats } from '../interfaces/IStats'; import { IStats } from '../interfaces/IStats';
...@@ -23,7 +23,7 @@ export class Game implements IGame { ...@@ -23,7 +23,7 @@ export class Game implements IGame {
this.lobby = lobby; this.lobby = lobby;
this.gameStatus = false; // game not finished this.gameStatus = false; // game not finished
this.gameId = Math.random().toString(36); this.gameId = Math.random().toString(36);
this.terrain = new Terrain(); this.terrain = new Terrain(5, 15, 10);
this.lastActionTimeStamp = Date.now(); this.lastActionTimeStamp = Date.now();
// insert the lobby users into the game and create a new stats object for each user // insert the lobby users into the game and create a new stats object for each user
...@@ -117,62 +117,15 @@ export class Game implements IGame { ...@@ -117,62 +117,15 @@ export class Game implements IGame {
calculateNextGameState(newGameState: IGame): boolean { calculateNextGameState(newGameState: IGame): boolean {
// verify that json is a valid IGame object // verify that json is a valid IGame object
// compare the current game state with the new game state // verify that gameStates are valid
if (newGameState.gameId !== this.gameId) { if (!validateGameState(this, newGameState)) {
log('Game ID mismatch'); log("Game state is not valid. Can't update game state.");
return false; return false;
} }
if (newGameState.gameStatus !== this.gameStatus) { this.setGameState(newGameState);
log('Game status mismatch'); this.toggleTurn();
return false;
}
if (newGameState.users.length !== this.users.length) {
log('User length mismatch');
return false;
}
// check if a projectile was fired (we assume that the projectile is always fired by the current user)
if (
true
// this.getUsers()[this.getCurrentTurn()][1].getAmmunition() !==
// newGameState.getUsers()[newGameState.getCurrentTurn()][1].getAmmunition()
) {
// check if projectile hit a tank (use the turret angle and the tank position)
if (checkProjectileHit(newGameState)) {
// The user that was hit is the one not having the current turn
const hitUserIndex = newGameState.currentTurn === 0 ? 1 : 0;
const hitUserStats = newGameState.users[hitUserIndex].stats;
// Decrease health by 1 of the user that was hit
const newHealth = hitUserStats.health - 1;
hitUserStats.health = newHealth;
// If health is 0, set health to 0 and set tank destroyed to true
const tankDestroyed = newHealth <= 0;
hitUserStats.health = tankDestroyed ? 0 : newHealth;
// Calculate new score
const shooterUserIndex = newGameState.currentTurn;
const shooterUserStats = newGameState.users[shooterUserIndex].stats;
// const currentScore = shooterUserStats.getScore();
// TODO this will not be saved.
// If tank destroyed, add 100 points to the score
// If tank not destroyed, add 10 points to the score
// const scoreIncrease = tankDestroyed ? 100 : 10;
// shooterUserStats.setScore(currentScore + scoreIncrease);
// if tank is destroyed, end the game
if (tankDestroyed) {
newGameState.gameStatus = false;
}
}
this.setGameState(newGameState);
this.toggleTurn();
}
log('Game state updated for game ' + this.gameId); log('Game state updated for game ' + this.gameId);
return true; return true;
} }
......
import generateYValues from '../functions/TerrainGenerator'; import generateYValues, { generateRandomNumbers } from '../functions/TerrainGenerator';
import { ITerrain } from '../interfaces/ITerrain'; import { ITerrain } from '../interfaces/ITerrain';
export class Terrain implements ITerrain { export class Terrain implements ITerrain {
yValues: number[]; yValues: number[];
maxY: number; minValue: number;
xPoints: number; maxValue: number;
n: number; // number of points to generate
constructor(maxY: number = 15, numValues: number = 1000) { constructor(minValue: number, maxValue: number, n: number) {
this.maxY = maxY; this.maxValue = maxValue;
this.xPoints = numValues; this.minValue = minValue;
this.n = n;
this.yValues = this.generate(); this.yValues = this.generate();
} }
generate(): number[] { generate(): number[] {
return generateYValues(this.maxY, this.xPoints); // return generateYValues(this.maxY, this.xPoints);
return generateRandomNumbers(this.n, this.minValue, this.maxValue);
} }
getYValues(): number[] { getYValues(): number[] {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment