Added JQuery, fixed offline, added start button

This commit is contained in:
Nikita Iryupin 2021-06-05 10:14:16 +02:00
parent e3d38cd730
commit 5526696c96
17 changed files with 347 additions and 25 deletions

Binary file not shown.

View File

@ -1,13 +1,48 @@
<!doctype html>
<html>
<head lang='en'>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width'>
<link rel="icon" href="./favicon.ico"/>
<link rel="icon" href="./favicon.ico" />
<link rel="stylesheet" href="./styles/main.css">
<link rel="stylesheet" href="./styles/tank-animation.css">
<title>BattleCity.js</title>
<script src='bundle.js'></script>
<script src="./libs/jquery-3.6.0.min.js"></script>
<script src='./bundle.js'></script>
</head>
<body>
<main><canvas id="canvas"></canvas></main>
<main class="wrapper">
<canvas id="canvas"></canvas>
<div class="loading">
<div class="center">
<div><div class="pixel"></div></div>
<div class="text-loading">Loading...</div>
<div class='container start-level-button'>
<a href='#' class='playBut'>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" x="0px" y="0px" width="213.7px"
height="213.7px" viewBox="0 0 213.7 213.7" enable-background="new 0 0 213.7 213.7"
xml:space="preserve">
<polygon class='triangle' id="XMLID_18_" fill="none" stroke-width="7" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" points="
73.5,62.5 148.5,105.8 73.5,149.1 " />
<circle class='circle' id="XMLID_17_" fill="none" stroke-width="7" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" cx="106.8" cy="106.8" r="103.3" />
</svg>
</a>
</div>
</div>
</div>
</main>
</body>
</html>

2
public/libs/jquery-3.6.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
public/sound/brick.ogg Normal file

Binary file not shown.

BIN
public/sound/explosion.ogg Normal file

Binary file not shown.

BIN
public/sound/gameover.ogg Normal file

Binary file not shown.

BIN
public/sound/gamestart.ogg Normal file

Binary file not shown.

BIN
public/sound/steel.ogg Normal file

Binary file not shown.

118
public/styles/main.css Normal file
View File

@ -0,0 +1,118 @@
@font-face {
font-family: VT323;
src : url(./../fonts/VT323-Regular.ttf);
}
body {
font-family: VT323, 'Common Pixel', sans-serif;
}
#canvas {
border: 1px solid #f8aa28;
border-radius: 1%;
}
.wrapper {
width : 416px;
height: 416px;
border: 1px solid #f8aa28;
border-radius: 1%;
position: relative;
}
.loading {
width : 100%;
height : 100%;
position : absolute;
top : 0px;
left : 0px;
background-color: black;
border: 1px solid #f8aa28;
border-radius: 1%;
}
.center {
display: flex;
flex-direction: column;
align-items: center;
justify-items: center;
}
.center:first-child {
margin-top: 5%;
text-align: center;
}
.text-loading {
color: white;
}
div.start-level-button {
display: none;
}
.container {
width : 100%;
text-align: center;
margin-top: 10vh;
}
.circle {
stroke : #f8aa28;
stroke-dasharray : 650;
stroke-dashoffset : 650;
-webkit-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
opacity : 0.3;
}
.playBut {
display : inline-block;
transition: all 0.5s ease;
-webkit-transition: all 0.5s ease;
}
.playBut .triangle {
-webkit-transition: all 0.7s ease-in-out;
transition: all 0.7s ease-in-out;
stroke-dasharray : 240;
stroke-dashoffset : 480;
stroke : #FFF;
transform : translateY(0)
}
.playBut:hover .triangle {
stroke-dashoffset: 0;
opacity : 1;
stroke : #f8aa28;
animation : nudge 0.7s ease-in-out;
@keyframes nudge {
0% {
transform: translateX(0)
}
30% {
transform: translateX(-5px)
}
50% {
transform: translateX(5px)
}
70% {
transform: translateX(-2px)
}
100% {
transform: translateX(0)
}
}
}
.playBut:hover .circle {
stroke-dashoffset: 0;
opacity : 1;
}

File diff suppressed because one or more lines are too long

43
public/sw.js Normal file
View File

@ -0,0 +1,43 @@
const filesToCache = [
"./",
"fonts/VT323-Regular.ttf",
"bundle.js",
"bundle.js.map",
"favicon.ico",
"nesBattle.png",
"sound/brick.ogg",
"sound/explosion.ogg",
"sound/gameover.ogg",
"sound/gamestart.ogg",
"sound/steel.ogg",
"styles/main.css",
"stages/stage-1.json",
"stages/stage-2.json",
"stages/stage-3.json",
"libs/jquery-3.6.0.min.js"
]
const cacheName = "battleCity";
self.addEventListener('install', event => {
self.skipWaiting();
event.waitUntil(
caches.open(cacheName).then(cache => cache.addAll(filesToCache))
);
});
self.addEventListener('fetch', event => {
event.respondWith (
caches.match(event.request).then(response => {
if (response) return response;
return fetch(event.request)
.then(response => {
if (response.ok)
return caches.open(cacheName).then(cache => {
cache.put(event.request.url, response.clone());
return response;
});
});
})
)
});

View File

@ -7,11 +7,15 @@ import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
external: ["jquery"],
input: 'src/main.js',
output: {
file: 'public/bundle.js',
format: 'iife', // immediately-invoked function expression — suitable for <script> tags
sourcemap: true
sourcemap: true,
globals: {
jquery: "$"
}
},
plugins: [
resolve(), // tells Rollup how to find date-fns in node_modules

View File

@ -2,6 +2,7 @@ import { BlockTypeEnum } from "../Blocks/blockTypeEnum";
import { Constants } from "../constants";
import { Map } from "../Graphics/Map/map";
import { Tank } from "../Tanks/tank";
import { SoundEnum, SoundManager } from "./soundManager";
export class CollisionManager {
/**
@ -20,6 +21,14 @@ export class CollisionManager {
_aiTanks = [];
/**
* @param {SoundManager} soundManager
*/
constructor(soundManager) {
this.soundManager = soundManager;
}
attachMap(map) {
this._map = map;
}
@ -56,6 +65,15 @@ export class CollisionManager {
if (blockColl) {
for (let blockInfo of Array.from(blockColl)) {
blockInfo.block.resolveAttack(blockInfo.boxId, direction);
switch(blockInfo.block.getType()) {
case BlockTypeEnum.Brick:
this.soundManager.playSound(SoundEnum.BrickCollision);
break;
case BlockTypeEnum.Iron:
this.soundManager.playSound(SoundEnum.SteelCollision);
break;
}
}
return true;
}
@ -67,6 +85,7 @@ export class CollisionManager {
if (collTank && collTank.id != tank.id) {
collTank.isDestroyed = true;
this.soundManager.playSound(SoundEnum.Explosion);
return true;
}
else {

View File

@ -6,6 +6,9 @@ import { MapParser } from "../Graphics/Map/mapParser";
import { CollisionManager } from "./collisionManager";
import { AITankManager } from "./../Tanks/aiTankManager";
import { DirectionEnum } from "../Tanks/directionEnum";
import { SoundEnum, SoundManager } from "./soundManager";
import $ from 'jquery';
export class GameField {
constructor(width = 512, height = 512, ctx, canvas) {
@ -16,9 +19,10 @@ export class GameField {
this.tileset = null;
this.map = null;
this.soundManager = new SoundManager();
this.collisionManager = new CollisionManager();
this.tank = new Tank(Constants.PLAYER_TANK_ID_IMAGE.getValue(), 0, 18*16, this.collisionManager);
this.collisionManager = new CollisionManager(this.soundManager);
this.tank = new Tank(Constants.PLAYER_TANK_ID_IMAGE.getValue(), 0, 18 * 16, this.collisionManager);
this.aiTanks = new AITankManager(this.collisionManager);
this.collisionManager.setMainTank(this.tank);
}
@ -55,36 +59,78 @@ export class GameField {
this.tileset.addTile(386, 0, 28, 28, 200 + DirectionEnum.Down.getValue());
this.tileset.addTile(452, 0, 28, 28, 200 + DirectionEnum.Right.getValue());
this.tileset.addTile(512, 8*32, 32, 32, BlockTypeEnum.Explosion1);
this.tileset.addTile(544, 8*32, 32, 32, BlockTypeEnum.Explosion2);
this.tileset.addTile(576, 8*32, 32, 32, BlockTypeEnum.Explosion3);
this.tileset.addTile(512, 8 * 32, 32, 32, BlockTypeEnum.Explosion1);
this.tileset.addTile(544, 8 * 32, 32, 32, BlockTypeEnum.Explosion2);
this.tileset.addTile(576, 8 * 32, 32, 32, BlockTypeEnum.Explosion3);
await this.tileset.loadAll();
}
async gameLoop() {
async prepareGame(level) {
if (!this.tileset) {
await this.setupTileset();
}
if (!this.map) {
this.map = await new MapParser().getMap(1, this.tileset);
this.canvas.height = this.height;
this.canvas.width = this.width;
this.collisionManager.attachMap(this.map);
this.aiTanks.setCount(this.map._enemiesCount);
this.map = await new MapParser().getMap(level, this.tileset);
this.canvas.height = this.height;
this.canvas.width = this.width;
this.collisionManager.attachMap(this.map);
this.aiTanks.setCount(this.map._enemiesCount);
}
async play(level) {
if (!this.tileset || !this.map) {
await this.prepareGame(level);
$(".text-loading").hide();
$(".start-level-button").show();
$(".start-level-button").on("click", () => {
$(".loading").hide();
this.soundManager.playSound(SoundEnum.GameStart);
requestAnimationFrame(() => this.gameLoop());
})
}
}
lose() {
this.soundManager.playSound(SoundEnum.GameOver);
requestAnimationFrame(() => this.drawFieldRecursive())
}
win() {
requestAnimationFrame(() => this.drawFieldRecursive())
}
async gameLoop() {
if (this.map.getEagle().isDestroyed()) {
this.lose();
return;
}
if (this.map.getEagle().isDestroyed()) return;
if (this.aiTanks.isAllTanksDied()) return;
if (this.tank.canBeErased()) return;
if (this.aiTanks.isAllTanksDied()) {
this.win();
return;
}
if (this.tank.canBeErased()) {
this.lose();
return;
}
this.drawField();
requestAnimationFrame(() => this.gameLoop());
}
drawFieldRecursive() {
this.drawField();
requestAnimationFrame(() => this.drawFieldRecursive());
}
drawField() {
let lateDraw = [];
@ -96,10 +142,9 @@ export class GameField {
Constants.TILE_SIZE.getValue(), Constants.TILE_SIZE.getValue());
let element = this.map.getElement(x, y);
if (element.getType() == BlockTypeEnum.Forest){
lateDraw.push({element, x, y});
} else
{
if (element.getType() == BlockTypeEnum.Forest) {
lateDraw.push({ element, x, y });
} else {
element.draw(this.ctx, x * Constants.TILE_SIZE.getValue(), y * Constants.TILE_SIZE.getValue());
}
}

View File

@ -0,0 +1,24 @@
import { Constants } from "../constants";
export class SoundManager {
playSound(soundEnum) {
if (soundEnum)
soundEnum.playSound();
}
}
export class SoundEnum {
static BrickCollision = new SoundEnum(Constants.BRICK_SOUND.getValue());
static SteelCollision = new SoundEnum(Constants.STEEL_SOUND.getValue());
static Explosion = new SoundEnum(Constants.EXPLOSION_SOUND.getValue());
static GameOver = new SoundEnum(Constants.GAME_OVER_SOUND.getValue());
static GameStart = new SoundEnum(Constants.GAME_START_SOUND.getValue());
playSound() {
this._audio.play();
}
constructor(URL) {
this._audio = new Audio(URL);
}
}

View File

@ -7,6 +7,12 @@ export class Constants {
static PLAYER_TANK_ID_IMAGE = new Constants(100);
static BRICK_SOUND = new Constants("sound/brick.ogg");
static STEEL_SOUND = new Constants("sound/steel.ogg");
static EXPLOSION_SOUND = new Constants("sound/explosion.ogg");
static GAME_START_SOUND = new Constants("sound/gamestart.ogg");
static GAME_OVER_SOUND = new Constants("sound/gameover.ogg");
constructor(value){
this._value = value;
}

View File

@ -2,12 +2,19 @@ import { GameField } from "./GameLogic/gameField";
import { TankKeyAdapter } from "./KeyAdapters/tankKeyAdapter";
export function init() {
if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('./sw.js')
.then(function() { console.log("Service Worker Registered"); });
}
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
const game = new Game(416, 416, ctx, canvas);
game.start();
}
}
export class Game {
@ -43,6 +50,6 @@ export class Game {
addEventListener("keyup", (ev) => {
if (prevEv && prevEv.key == ev.key) prevEv = undefined;
});
requestAnimationFrame(() => this.gameField.gameLoop());
requestAnimationFrame(() => this.gameField.play(1));
}
}