///////////////////// const canvas = document.querySelector("#gameCanvas"); const intro_canvas = document.querySelector("#introCanvas"); const text_canvas = document.querySelector("#textCanvas"); const ctx = canvas.getContext('2d'); const intro_ctx = intro_canvas.getContext('2d'); const text_ctx = text_canvas.getContext('2d'); const black_color = "#1B1212"; var game, round = 1, bot_win = 0, player_win = 0, images, arrow_down, mouse_down; var key_down = []; // действия, привязанные к нажатым кнопкам var keyboard_pressed = []; // зажатые кнопки клавиатуры var btn_pressed = []; // нажатые gui кнопки канваса const frame_data = []; var selected_level = 1; const directions = { "_Left" : -1, "_Right" : 1, }; const actions = ["punch", "jump", "block"]; const levels = ["gg_cabinet", "bar", "car_salon"]; function loaderPicture(path){ const image = new Image(); image.src = path; return new Promise((resolve, reject) => { image.addEventListener('load', ()=>{ resolve(image); }); image.addEventListener('error', ()=>{ reject("Error of load"); }); }) } function setFrameData(level){ frame_data["Игрок"] = new FrameData(timing["player"].value); frame_data["Компьютер"] = new FrameData(timing[levels[level] + "_enemy_timing"].value); // frame_data["Бармэн"] = new FrameData(bar_enemy_timing); for(var name in frame_data){ for(var key in frame_data[name]){ // есть start в свойстве класса и есть такой же ключ в тайминге if("start" in frame_data[name][key] && frame_data[name].timing[key]){ frame_data[name][key].start = frame_data[name].timing[key].start; frame_data[name][key].end = frame_data[name].timing[key].end; if(frame_data[name].timing[key].speed){ frame_data[name][key].speed = frame_data[name].timing[key].speed; } if(frame_data[name].timing[key].active){ frame_data[name][key].active = frame_data[name].timing[key].active; } } } } } function beforeGame(){ game.start_menu = false; game.over = true; game.intro = true; setFrameData(selected_level); let player = new Player(canvas.width, canvas.height, game.images.player, 0, "player", "Игрок"); game.player = player; game.characters = { player: player, enemy: new Enemy(canvas.width, canvas.height, game.images["enemy" + (selected_level + 1)], 500, "bot", "Компьютер", timing[levels[selected_level] + "_enemy_timing"].size.w, timing[levels[selected_level] + "_enemy_timing"].size.h, timing[levels[selected_level] + "_enemy_timing"].speed ), // npc: new Player(canvas.width, canvas.height, images.enemy2, 800, "npc", "Бармэн", 148, 200, 2) } game.buttons.button1.caption = ""; game.buttons.button2.caption = ""; game.buttons.button3.caption = ""; } const keyToFrame = { 'ArrowLeft': 'walk_Left', 'ArrowRight': 'walk_Right', 'ArrowDown': 'crouch', 'q': 'punch', 'w': 'block', 'e': 'block_Up', 's': 'kick_Up', ' ': 'jump', // 'x,z': 'test' }; const test_actions = [ 'punch_Left', 'kick_Left_Up', 'crouch_Left_Down', 'block_Left_Up', 'stand_Left', 'jump_Left', ] function getRand(min, max){ min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min } class Game{ constructor(canvas, images, start = true){ this.images = images; this.ui = null; this.start_menu = start; this.over = true; this.intro = false; this.timer = 0; this.delta = 0; this.interval = 3 * 1.5; // скорость обновления канваса this.info_animation_timer = undefined; this.start_screen_timer = 0; this.start_screen_delta = 0; this.round_time = 60; this.round_amount = 3; this.time_bar = new Button(text_ctx, 5 * 1.5, 0.2, 100 / 1.5, 50 / 1.5 ); this.buttons = []; this.buttons["button1"] = new Button(text_ctx, 0.82, 2, 400, 50 ); this.buttons["button2"] = new Button(text_ctx, 0.82, 3.5, 400, 50 ); this.buttons["button3"] = new Button(text_ctx, 0.82, 5, 400, 50 ); const w = 100; this.buttons["q"] = new Button(text_ctx, 0.5, 0.25, w, w ); this.buttons["w"] = new Button(text_ctx, 2, 0.25, w, w ); this.buttons["e"] = new Button(text_ctx, 3.5, 0.25, w, w ); this.buttons["a"] = new Button(text_ctx, 1, 1.5, w, w ); this.buttons["s"] = new Button(text_ctx, 2.5, 1.5, w, w ); this.buttons["d"] = new Button(text_ctx, 4, 1.5, w, w ); this.buttons["left"] = new Button(text_ctx, 7.5, 0.25, w, w ); this.buttons["right"] = new Button(text_ctx, 9, 0.25, w, w ); this.buttons["down"] = new Button(text_ctx, 8.25, 1.5, w, w ); this.buttons["space"] = new Button(text_ctx, 1.5 / 8.5, 2.75, w * 8.5, w ); this.buttons["title"] = new Button(text_ctx, 4.5 / 3, 0.25, w * 3, w ); this.buttons["close"] = new Button(text_ctx, 40.5, 0.5, w / 4, w / 4 ); this.buttons["bottom_text"] = new Button(text_ctx, 0.6, 11.3, w * 5, w / 3 ); this.info_animation = [ {button: "q", action: "punch_Right"}, {button: "w", action: "block_Right"}, {button: "e", action: "block_Right_Up"}, {button: "s", action: "kick_Right_Up"}, {button: "left", action: "walk_Left"}, {button: "right", action: "walk_Right"}, {button: "down", action: "crouch_Right_Down"}, {button: "down_q", action: "punch_Right_Down"}, {button: "down_w", action: "block_Right_Down"}, {button: "space", action: "jump_Right"} ]; this.ui = new UI(); } updateAll(key){ // if(this.characters.npc.currentFrame == 0){ // this.characters.npc.currentAction = test_actions[getRand(0, 5)]; // } if(!this.start_menu){ ctx.drawImage(this.images["background" + (selected_level + 1)], 0, 0, canvas.width, canvas.height); } else{ ctx.fillStyle = black_color; ctx.fillRect(0, 0, canvas.width, canvas.height); } if(this.over){ if(!this.start_menu){ if(!this.intro){ if(!this.buttons.button2.caption){ setTimeout(function(){ game.ui.clearAll(); game.buttons.button2.background = "purple"; game.buttons.button2.caption = "Press to continue"; }, 1000); } else{ this.buttons.button2.background = "purple"; this.buttons.button2.caption = "Press to continue"; } } } else if(this.ui){ for(var i in this.buttons){ var button = this.buttons[i]; if(button.caption){ if(button.focus){ button.background = "orange"; } else{ button.background = "purple"; } } } if(game.info_animation_timer == undefined){ this.buttons.button1.caption = "Chief cabinet"; this.buttons.button2.caption = "Bar room"; this.buttons.button3.caption = "Car showroom"; } else{ this.buttons.button1.caption = ""; this.buttons.button2.caption = ""; this.buttons.button3.caption = ""; } } if(game.info_animation_timer != undefined){ this.buttons.title.background = black_color; this.buttons.bottom_text.background = black_color; this.buttons.close.background = "maroon"; } } // for(let key in this.characters){ // this.characters[key].update(); // } if(!this.over){ if(this.player){ this.player.update(); } if(this.characters && this.characters.enemy){ this.characters.enemy.update(); } } if(!this.start_menu){ this.start_screen_timer += 1; const vs_delay = 60; if(this.start_screen_timer > vs_delay){ this.start_screen_delta += 20; } if(!this.over && this.characters){ this.ui.drawUserInfo(50, 50, 200, images.player_avatar, this.player, this.player.name, 210); this.ui.drawUserInfo(canvas.width - 250, 50, 200, images["bot_avatar" + (selected_level + 1)], this.characters.enemy, this.characters.enemy.name, -70); // this.ui.clearAll(); // this.ui.drawTimeBar(intro_ctx, images.time_bar, false, 0, 1.5); // this.ui.drawTimeBar(text_ctx, images.time_bar_mask, true, 0, 1.5); } if(this.intro){ this.ui.drawStartScreen(images.player_avatar, images["bot_avatar" + (selected_level + 1)], "", this.start_screen_delta, vs_delay); if(this.start_screen_timer > vs_delay){ this.ui.drawGameCaption(intro_ctx, images.fight, false, this.start_screen_delta); this.ui.drawGameCaption(text_ctx, images.fight, true, this.start_screen_delta); } else if(this.start_screen_timer > vs_delay / 2){ this.ui.drawGameCaption(text_ctx, images["round" + round], false, this.start_screen_delta); } else{ this.ui.drawGameCaption(text_ctx, images.vs, false, this.start_screen_delta); } if(this.start_screen_delta >= canvas.width / 2){ this.ui.clearAll(); this.intro = false; this.over = false; } } if(!this.over){ this.timer++; } // 60 fps канваса, но функция выывается в interval раз реже this.seconds = Math.floor(this.timer / (60 / this.interval) ); if(this.seconds >= this.round_time && !this.over && this.characters.enemy){ this.over = true; if(this.player.health.current < this.characters.enemy.health.current){ bot_win++; round++; } if(this.player.health.current >= this.characters.enemy.health.current){ player_win++; round++; } this.checkWin(); } } if(this.info_animation_timer != undefined){ this.buttons.q.caption = "Q"; this.buttons.w.caption = "W"; this.buttons.e.caption = "E"; this.buttons.a.caption = "A"; this.buttons.s.caption = "S"; this.buttons.d.caption = "D"; this.buttons.left.caption = "<"; this.buttons.right.caption = ">"; this.buttons.down.caption = "|"; this.buttons.space.caption = " "; this.buttons.close.caption = "X"; this.buttons.bottom_text.caption = "look or press keyboard yourself"; const index = Math.round(this.info_animation_timer / 30); const obj = this.info_animation[index]; if(index < this.info_animation.length){ if(Object.keys(btn_pressed).length == 0){ this.info_animation_timer++; if(obj){ const action = timing["player"].value[obj.action]; const frameWidth = 224; const frameHeight = 200; const image = game.images.player; // const x = 100; // const y = 100; const { start, end } = action; const rate = 10; const frames = this.info_animation_timer % rate if(this.info_animation[index - 1]){ const previous_obj = this.info_animation[index - 1]; const previous_button = previous_obj.button.split("_"); if(!previous_button[1]){ this.buttons[previous_button[0]].focus = false; } else{ this.buttons[previous_button[0]].focus = false; this.buttons[previous_button[1]].focus = false; } } const button = obj.button.split("_"); if(!button[1]){ this.buttons[button[0]].focus = true; } else{ this.buttons[button[0]].focus = true; this.buttons[button[1]].focus = true; } if(frames && this.player.currentFrame == 0){ if(key_down[obj.action] != false){ if(obj.action == "walk_Right"){ this.player.direction = "_Right"; } key_down[obj.action] = true; } } } } else{ for(var i in this.buttons){ this.buttons[i].focus = false; } for(var i in btn_pressed){ if(this.buttons[i]){ this.buttons[i].focus = true; } } } if(this.player){ if(Object.keys(btn_pressed).length == 0){ var first_part = obj.action.split("_"); } else{ var first_part = this.player.currentAction.split("_"); } var direction_vert = first_part[2]; if(direction_vert == "Up"){ var str = direction_vert.toLowerCase(); } else{ var str = ""; } this.buttons.title.caption = first_part[0] + " " + str; this.player.update(); } } else{ this.info_animation_timer = undefined; key_down = {}; beforeGame(); } this.player.stopped = true; } else{ this.buttons.q.caption = ""; this.buttons.w.caption = ""; this.buttons.e.caption = ""; this.buttons.a.caption = ""; this.buttons.s.caption = ""; this.buttons.d.caption = ""; this.buttons.left.caption = ""; this.buttons.right.caption = ""; this.buttons.down.caption = ""; this.buttons.space.caption = ""; } } checkWin(){ if(round <= this.round_amount && player_win != 2 && bot_win != 2){ firstState(false); beforeGame(); } else if(!this.buttons.button2.caption){ if(bot_win > player_win){ this.ui.drawGameCaption(text_ctx, images.over, false, this.start_screen_delta); } else{ this.ui.drawGameCaption(text_ctx, images.win, false, this.start_screen_delta); } } } } function runGame(){ game.delta++; if (game.delta > game.interval) { game.updateAll(); game.delta = 0; } requestAnimationFrame(runGame); } window.addEventListener("load", start); function firstState(start = true){ const container = document.querySelector(".container"); const css_string = "position: absolute;" canvas.style.cssText = css_string + "z-index: 0"; intro_canvas.style.cssText = css_string + "z-index: 1"; text_canvas.style.cssText = css_string + "z-index: 2"; document.body.style.cssText = "display: flex; justify-content: center; height: 100vh; align-items: center"; // document.body.style.background = "black"; document.body.style.overflow = "hidden"; document.body.style.margin = "0"; canvas.width = intro_canvas.width = text_canvas.width = images.background1.width; canvas.height = intro_canvas.height = text_canvas.height = images.background1.height; container.style.width = canvas.width + "px"; container.style.height = canvas.height + "px"; game = new Game(canvas, images, start); } async function start(){ images = { background1: await loaderPicture("./content/background1.png"), background2: await loaderPicture("./content/background2.png"), background3: await loaderPicture("./content/background3.png"), player: await loaderPicture("./content/player.png"), enemy1: await loaderPicture("./content/enemy1.png"), enemy2: await loaderPicture("./content/enemy2.png"), enemy3: await loaderPicture("./content/enemy3.png"), over: await loaderPicture("./content/over.png"), win: await loaderPicture("./content/win.png"), player_avatar: await loaderPicture("./content/player_avatar.png"), bot_avatar1: await loaderPicture("./content/bot_avatar1.png"), bot_avatar2: await loaderPicture("./content/bot_avatar2.png"), bot_avatar3: await loaderPicture("./content/bot_avatar3.png"), player_avatar_rage: await loaderPicture("./content/player_avatar_rage.png"), bot_avatar_rage: await loaderPicture("./content/bot_avatar_rage.png"), fight: await loaderPicture("./content/fight.png"), vs: await loaderPicture("./content/vs.png"), round1: await loaderPicture("./content/round1.png"), round2: await loaderPicture("./content/round2.png"), round3: await loaderPicture("./content/round3.png"), time_bar: await loaderPicture("./content/time_bar.png"), time_bar_mask: await loaderPicture("./content/time_bar_mask.png"), lock: await loaderPicture("./content/lock.png"), block: await loaderPicture("./content/block.png"), } window.loading_text = document.querySelector('.top-div'); loading_text.style.display= "none"; firstState(); // beforeGame(); // здесь для теста runGame(game); // game.over = false; // здесь для теста // game.intro = false; // здесь для теста window.addEventListener('resize', event => { canvas.width = images.background1.width; canvas.height = images.background1.height; }) document.addEventListener('keydown', event => { if(game.player){ if(event.code.toLowerCase().split("key")[1]){ var key = event.code.toLowerCase().split("key")[1]; // e.key привязан к раскладке, поэтому берем e.code. // Если клавиша с буквой, то забираем код и берем из него название буквы. // Например, для клавиши "А" код "KeyA", значит переменная index будет "A". } else{// Клавиши без букв, например, стрелки. Для них можно использовать и e.code var key = event.key; } if(keyboard_pressed.indexOf(key) == -1 && (!key.split("Arrow")[1] || keyboard_pressed.length == 0) ){ keyboard_pressed.push(key); } else{ return; } var index = keyboard_pressed.sort().toString(); if(!keyToFrame[index]){ index = key; if(!keyToFrame[index]){ // продолжаем, если есть такое действие return; } } const direction_hor = game.player.direction; const name = keyToFrame[index].split("_"); const str = name[0]; // содержит "_Up" в конце const str2 = name[1]; // флаг для нижних ударов. if(index == "ArrowDown"){ arrow_down = true; } if(str2){ var direction_vert = "_" + str2; } else if(arrow_down){ var direction_vert = "_Down"; } else{ var direction_vert = ""; } if(index == "ArrowLeft" || index == "ArrowRight"){ key_down[keyToFrame[index]] = true; // console.log(index) } else if(game.player[str + direction_hor + direction_vert]){ key_down[str + direction_hor + direction_vert] = true; } } // Ниндзя код var k = event.code; var n = k.toLowerCase() == "space" ? "space" : k.toLowerCase().split("key")[1] || k.toLowerCase().split("arrow")[1]; if(n){ btn_pressed[n] = true; if(game.buttons[n]){ game.buttons[n].focus = true; } } }); document.addEventListener('keyup', event => { if(event.code.toLowerCase().split("key")[1]){ var key = event.code.toLowerCase().split("key")[1]; // e.key привязан к раскладке, поэтому берем e.code. // Если клавиша с буквой, то забираем код и берем из него название буквы. // Например, для клавиши "А" код "KeyA", значит переменная index будет "A". } else{// Клавиши без букв, например, стрелки. Для них можно использовать и e.code var key = event.key; } const index = key; if(game.player && game.player.direction){ const direction_hor = game.player.direction; if(keyToFrame[index]){ const name = keyToFrame[index].split("_"); const str = name[0]; // содержит "_Up" в конце const str2 = name[1]; if(str2){ var direction_vert = "_" + str2; } else if(arrow_down){ var direction_vert = "_Down"; } else{ var direction_vert = ""; } if(index == "ArrowLeft" || index == "ArrowRight"){ delete key_down[keyToFrame[index]]; } else if(game.player[str + direction_hor + direction_vert]){ console.log(index, str + direction_hor + direction_vert) delete key_down[str + direction_hor + direction_vert]; } } } // Ниндзя код var k = event.code; var n = k.toLowerCase() == "space" ? "space" : k.toLowerCase().split("key")[1] || k.toLowerCase().split("arrow")[1]; if(n){ delete btn_pressed[n]; if(game.buttons[n]){ game.buttons[n].focus = false; } } // Если не зажата кнопка "Вниз", сбрасываем индикатор зажатой клавиши if(index == "ArrowDown"){ arrow_down = false; } if(keyboard_pressed.indexOf(index) >= 0){ keyboard_pressed.splice(keyboard_pressed.indexOf(index), 1); } }); text_canvas.addEventListener('mousemove', event => { if(game.over && game.info_animation_timer == undefined){ for(var i in game.buttons){ var button = game.buttons[i]; if(button && button.caption){ if(event.offsetX > button.x * button.width && event.offsetX < button.x * button.width + button.width && event.offsetY > button.y * button.height && event.offsetY < button.y * button.height + button.height){ button.focus = true; return; } else{ button.focus = false; } } } } }); text_canvas.addEventListener('mousedown', event => { for(var i in game.buttons){ var button = game.buttons[i]; if(button && button.caption){ if(event.offsetX > button.x * button.width && event.offsetX < button.x * button.width + button.width && event.offsetY > button.y * button.height && event.offsetY < button.y * button.height + button.height){ button.pressed = true; if(!isNaN(Number(i.split("button")[1]) - 1) ){ selected_level = Number(i.split("button")[1]) - 1; } if(i == "close"){ game.info_animation_timer = undefined; key_down = {}; beforeGame(); return; } // Не средняя кнопка if(game.start_menu){ game.info_animation_timer = 0; setFrameData(selected_level); let player = new Player(canvas.width, canvas.height, game.images.player, 450, "player", "Игрок", undefined, undefined, undefined, 1.5) game.player = player; game.characters = { player: player, } } else{ alert("Следующий уровень") game.over = true; return; } return; } else{ button.pressed = false; } } } }); }