commit a5247d668d326da1ffdf4b04b291865d27e24b9b Author: Oleg Date: Sat Aug 16 10:24:23 2025 +0000 first commit diff --git a/battle.js b/battle.js new file mode 100644 index 0000000..54ff124 --- /dev/null +++ b/battle.js @@ -0,0 +1,703 @@ +///////////////////// +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; + } + } + } + }); +} diff --git a/chars.js b/chars.js new file mode 100644 index 0000000..8cac7da --- /dev/null +++ b/chars.js @@ -0,0 +1,76 @@ +var letters = []; + letters["A"] = [[0,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["B"] = [[1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0]]; + letters["C"] = [[0,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1]]; + letters["D"] = [[1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1]]; + letters["E"] = [[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1]]; + letters["F"] = [[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]]; + letters["G"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,0,0,0,0],[1,0,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["H"] = [[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["I"] = [[1,1,1,1,1],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,1,1,1,1]]; + letters["J"] = [[1,1,1,1,1],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,1,1,0,0]]; + letters["K"] = [[1,0,0,0,1],[1,0,0,1,0],[1,0,0,1,0],[1,1,1,0,0],[1,0,0,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["L"] = [[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1]]; + letters["M"] = [[1,0,0,0,1],[1,0,0,0,1],[1,1,0,1,1],[1,0,1,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["N"] = [[1,0,0,0,1],[1,1,0,0,1],[1,0,1,0,1],[1,0,0,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["O"] = [[0,1,1,1],[1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0],[1,0,0,0,1],[0,1,1,1]]; + letters["P"] = [[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]]; + letters["Q"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,1,0],[0,1,1,1,1]]; + letters["R"] = [[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,1,0],[1,0,0,0,1],[1,0,0,0,1]]; + letters["S"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,1,0,0,0],[0,0,1,1,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["T"] = [[1,1,1,1,1],[0,0,1,0,0,null,0,null,null,null,0],[0,0,1,0,0,null,0,0,null,0,0],[0,0,1,0,0,null,0,null,0,null,0],[0,0,1,0,0,null,0],[0,0,1,0,0,null,0],[0,0,1,0,0,null,0],[0,0,1,0,0,null,0]]; + letters["U"] = [[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["V"] = [[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0]]; + letters["W"] = [[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,1,0,1],[1,1,0,1,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["X"] = [[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,1,0,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]]; + letters["Y"] = [[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0]]; + letters["Z"] = [[1,1,1,1,1],[1,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0],[1,0,0,0,1],[1,1,1,1,1]]; + letters[" "] = [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]; + letters["a"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[0,0,0,0,1,0,0,0,0,0,0],[0,1,1,1,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[0,1,1,1,1,0,0]]; + letters["b"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,1,1,1,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,1,1,1,0,0,0]]; + letters["c"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[0,1,1,1,0,0,0]]; + letters["d"] = [[0,0,0,0,1],[0,0,0,0,1,0,0,0,0,0,0],[0,0,0,0,1,0,0,0,0,0,0],[1,1,1,1,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,1,1,1,1,0,0]]; + letters["e"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,1,1,1,1,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0],[0,1,1,1,0,0,0]]; + letters["f"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,1,1,1,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0]]; + letters["g"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,1,1,0,0],[0,1,1,0,1,0,0],[0,0,0,0,1,0,0],[0,1,1,1,1,0,0]]; + letters["h"] = [[1,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0]]; + letters["i"] = [[0,0,1,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[1,1,1,1,1,0,0]]; + letters["j"] = [[0,0,1,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[1,1,1,0,0,0,0]]; + letters["k"] = [[1,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,1,0,0,0,0,0,0,0],[1,0,1,0,0,0,0,0,0,0,0],[1,1,1,1,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0]]; + letters["l"] = [[0,1,1,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[1,1,1,1,1,0,0]]; + letters["m"] = [[0,0,0,0,0],[1,1,1,1,0,0,0,0,0,0,0],[1,0,1,0,1,0,0,0,0,0,0],[1,0,1,0,1,0,0,0,0,0,0],[1,0,1,0,1,0,0],[1,0,1,0,1,0,0],[1,0,1,0,1,0,0],[1,0,1,0,1,0,0]]; + letters["n"] = [[0,0,0,0,0],[1,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0]]; + letters["o"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[0,1,1,1,0,0,0]]; + letters["p"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,1,1,1,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0]]; + letters["q"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[0,1,1,1,1,0,0],[0,0,0,0,1,0,0],[0,0,0,0,1,0,0]]; + letters["r"] = [[0,0,0,0,0],[1,0,1,1,0,0,0,0,0,0,0],[1,1,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0]]; + letters["s"] = [[0,0,0,0,0],[0,1,1,1,0,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,1,0,0,0,0,0,0,0,0,0],[0,0,1,1,0,0,0],[0,0,0,0,1,0,0],[1,0,0,0,1,0,0],[0,1,1,1,0,0,0]]; + letters["t"] = [[0,0,1,0,0],[1,1,1,1,1,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,0,0,0,0],[0,0,1,1,0,0,0]]; + letters["u"] = [[0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,0,1,1,0,0],[0,1,1,0,1,0,0]]; + letters["v"] = [[0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,1,0,0,0],[0,1,1,0,0,0,0],[0,1,0,0,0,0,0]]; + letters["w"] = [[0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[1,0,1,0,1,0,0],[0,1,0,1,0,0,0]]; + letters["x"] = [[0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[0,1,0,1,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0],[0,1,0,1,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,0],[0,0,0,0,0,0,0]]; + letters["y"] = [[0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[0,1,1,1,1,0,0,0,0,0,0],[0,0,0,0,1,0,0],[0,0,0,1,1,0,0],[0,1,1,0,0,0,0],[0,0,0,0,0,0,0]]; + letters["z"] = [[0,0,0,0,0],[1,1,1,1,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,1,0,0,1,0,0],[1,1,1,1,1,0,0],[0,0,0,0,0,0,0]]; + letters["-"] = [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[1,1,1,1,1],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]; + + letters["("] = [[0,0,1,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,0,1,0,0]]; + letters[")"] = [[0,0,1,0,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,1,0,0]]; + letters["."] = [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,1,0,0,0]]; + letters[","] = [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,1,0,0,0],[0,1,0,0,0]]; + letters[":"] = [[0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0]]; + letters["!"] = [[1,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0],[1,0,0,0,0,0,0],[0,0,0,0,0,0,0],[1,0,0,0,0,0,0]]; + letters["?"] = [[0,1,1,1,0],[1,0,0,0,1,0,0,0,0,0,0],[1,0,0,0,1,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,0,0,0,0,0],[0,0,1,0,0,0,0],[0,0,0,0,0,0,0]]; + letters["1"] = [[0,0,1,0,0],[0,1,1,0,0],[1,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,1,1,1,1]]; + letters["2"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0],[1,1,1,1,1]]; + letters["3"] = [[0,1,1,1,0],[1,0,0,0,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["4"] = [[0,0,0,1,1],[0,0,1,0,1],[0,1,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,0,1]]; + letters["5"] = [[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,0],[0,0,0,0,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["6"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["7"] = [[1,1,1,1,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]]; + letters["8"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["9"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["0"] = [[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]]; + letters["<"] = [[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0]]; + letters[">"] = [[0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0]]; + letters["|"] = [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,1,0,1,0],[0,0,1,0,0]]; \ No newline at end of file diff --git a/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (2).png b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (2).png new file mode 100644 index 0000000..add3ac1 Binary files /dev/null and b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (2).png differ diff --git a/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (3).png b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (3).png new file mode 100644 index 0000000..add3ac1 Binary files /dev/null and b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (3).png differ diff --git a/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (4).png b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (4).png new file mode 100644 index 0000000..add3ac1 Binary files /dev/null and b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (4).png differ diff --git a/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (5).png b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (5).png new file mode 100644 index 0000000..add3ac1 Binary files /dev/null and b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f (5).png differ diff --git a/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f.png b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f.png new file mode 100644 index 0000000..add3ac1 Binary files /dev/null and b/content/#U0434#U043e#U043a #U043e#U0434#U0438#U043d #U2014 #U043a#U043e#U043f#U0438#U044f.png differ diff --git a/content/background1.png b/content/background1.png new file mode 100644 index 0000000..f4cf5b0 Binary files /dev/null and b/content/background1.png differ diff --git a/content/background2.png b/content/background2.png new file mode 100644 index 0000000..8bed94e Binary files /dev/null and b/content/background2.png differ diff --git a/content/background3.png b/content/background3.png new file mode 100644 index 0000000..86192bf Binary files /dev/null and b/content/background3.png differ diff --git a/content/block.png b/content/block.png new file mode 100644 index 0000000..00e5b29 Binary files /dev/null and b/content/block.png differ diff --git a/content/bot_avatar1.png b/content/bot_avatar1.png new file mode 100644 index 0000000..c214bac Binary files /dev/null and b/content/bot_avatar1.png differ diff --git a/content/bot_avatar2.png b/content/bot_avatar2.png new file mode 100644 index 0000000..0590055 Binary files /dev/null and b/content/bot_avatar2.png differ diff --git a/content/bot_avatar3.png b/content/bot_avatar3.png new file mode 100644 index 0000000..0f398a6 Binary files /dev/null and b/content/bot_avatar3.png differ diff --git a/content/bot_avatar_rage.png b/content/bot_avatar_rage.png new file mode 100644 index 0000000..179e36a Binary files /dev/null and b/content/bot_avatar_rage.png differ diff --git a/content/enemy1.png b/content/enemy1.png new file mode 100644 index 0000000..8f46ee4 Binary files /dev/null and b/content/enemy1.png differ diff --git a/content/enemy2.png b/content/enemy2.png new file mode 100644 index 0000000..2d75b0d Binary files /dev/null and b/content/enemy2.png differ diff --git a/content/enemy3.png b/content/enemy3.png new file mode 100644 index 0000000..91eafa8 Binary files /dev/null and b/content/enemy3.png differ diff --git a/content/fight.png b/content/fight.png new file mode 100644 index 0000000..0a5e074 Binary files /dev/null and b/content/fight.png differ diff --git a/content/lock.png b/content/lock.png new file mode 100644 index 0000000..91866db Binary files /dev/null and b/content/lock.png differ diff --git a/content/over.png b/content/over.png new file mode 100644 index 0000000..7642396 Binary files /dev/null and b/content/over.png differ diff --git a/content/player.png b/content/player.png new file mode 100644 index 0000000..0b18f1d Binary files /dev/null and b/content/player.png differ diff --git a/content/player_avatar.png b/content/player_avatar.png new file mode 100644 index 0000000..480fa44 Binary files /dev/null and b/content/player_avatar.png differ diff --git a/content/player_avatar_rage.png b/content/player_avatar_rage.png new file mode 100644 index 0000000..c0fee37 Binary files /dev/null and b/content/player_avatar_rage.png differ diff --git a/content/round1.png b/content/round1.png new file mode 100644 index 0000000..29e290e Binary files /dev/null and b/content/round1.png differ diff --git a/content/round2.png b/content/round2.png new file mode 100644 index 0000000..eee258c Binary files /dev/null and b/content/round2.png differ diff --git a/content/round3.png b/content/round3.png new file mode 100644 index 0000000..17f740e Binary files /dev/null and b/content/round3.png differ diff --git a/content/time_bar.png b/content/time_bar.png new file mode 100644 index 0000000..039fbfe Binary files /dev/null and b/content/time_bar.png differ diff --git a/content/time_bar_mask.png b/content/time_bar_mask.png new file mode 100644 index 0000000..4da1f89 Binary files /dev/null and b/content/time_bar_mask.png differ diff --git a/content/vs.png b/content/vs.png new file mode 100644 index 0000000..d59160a Binary files /dev/null and b/content/vs.png differ diff --git a/content/win.png b/content/win.png new file mode 100644 index 0000000..a16d7ac Binary files /dev/null and b/content/win.png differ diff --git a/enemy.js b/enemy.js new file mode 100644 index 0000000..efc818c --- /dev/null +++ b/enemy.js @@ -0,0 +1,87 @@ +class Enemy extends Player{ + constructor(w, h, image, dx, type, name, frameWidth, frameHeight, frameSpeed, size){ + super(w, h, image, dx, type, name, frameWidth, frameHeight, frameSpeed, size); + } + reaction(nemesis_action_params){ + // Если противник встал, то мы тоже встаем + if(this.nemesis && this.nemesis.currentAction == "crouch" + this.nemesis.direction + "_Up"){ + this.currentFrame = 0; + this.crouch = false; + } + // Если предыдущая анимация завершилась или мы присели (тогда + // текущий кадр будет равен последнему кадру анимации) + if(this.currentFrame == 0 || frame_data[this.name][this.currentAction].no_return + && this.currentFrame >= frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1){ + this.idleCount = 0; + if( "reaction" in nemesis_action_params){ + const rand = getRand(1, 100); // число для случайного ответа + for(var obj of nemesis_action_params.reaction){ + const range = obj.chance.split("-"); + // если число в диапазоне + if(rand >= range[0] && rand < range[1]){ + // В это условие мы попадаем в двух случаях: Если идет бой + // или мы приблизились на расстояние, когда бот начинает подбегать к нам. + // Здесь мы вызываем реакцию из объекта nemesis_action_params + // Реакция это имя действия ("walk", "punch", "stand") плюс направление + // по горизонтали ("_Left" или "_Right"), плюс направление по вертикали — + // "Up", "Down", или "". Направление по вертикали это либо имя реакции плюс + // вертикальное направление удара врага (например, враг бьет сверху kick_Left_Up, + // тогда наша рекация будет "block" + "_Right" + "_Up"), либо имя реакции может отсылать + // к действию, которое само содержит в названии "_Up", тогда так же добавляем его к имени/ + // Либо это удары "punch", "block", "crouch" — тогда добавляем третий параметр + // после "_" в названии удара противника (то есть верхним ударам соотвествуют верхние, + // средним средние, нижним нижние) + if(this.nemesis){ + const nemesis_action = this.nemesis.currentAction; + var nemesis_action_name = this.nemesis.currentAction.split("_")[0]; + var nemesis_action_vert_direct = this.nemesis.currentAction.split("_")[2]; + } + if( (obj.name == "punch" || obj.name == "block" || obj.name == "crouch") + && this.nemesis && nemesis_action_vert_direct){ + if(obj.name != "punch"){ + var vert_direct = "_" + nemesis_action_vert_direct; + } + else{ + var vert_direct = ""; + } + } + // у kick только верхняя она удара + else if(obj.name == "kick"){ + var vert_direct = "_Up" ; + } + else{ + var vert_direct = ""; + } + + const action_name = obj.name + this.direction + vert_direct; + // Если бот присел и ничего не делает (то есть action_name == "crouch"), + // то doAction не вызываем, + // вызывается, если он производит действие — блок, удар и тп + + const condition = !this.crouch || action_name != "crouch" + this.direction + "_Down"; + if(condition){ + this.doAction(action_name, this.crouch); + break; + } + } + } + } + } + } + collision(){ + super.collision(); + if(this.potential_nemesis && !this.potential_nemesis.dy){ + if(!this.stopped){ + // подбегаем, если дистанция между противниками меньше нужной величины + // или бездействие больше определенной величины (увеличивается в update класса Player) + if(this.collision_distance > this.min_distance && (this.collision_distance < this.max_distance || this.idleCount > this.maxIdle) ){ + // если игрок на дистанции больше и меньше определенного значения, + // то бот реагирует как на действие walk в его направлении + if(!this.complex){ + this.reaction(frame_data[this.name]["walk" + this.potential_nemesis.direction]); + } + } + } + } + } +} diff --git a/frame_data.js b/frame_data.js new file mode 100644 index 0000000..96bf60a --- /dev/null +++ b/frame_data.js @@ -0,0 +1,221 @@ +const timing = { + player: { + value: { + punch_Right: {start: 0, end: 9}, + punch_Left: {start: 10, end: 18}, + punch_Right_Down: {start: 105, end: 112}, + punch_Left_Down: {start: 113, end: 120}, + block_Right: {start: 19, end: 27}, + block_Left: {start: 28, end: 36}, + block_Right_Up: {start: 37, end: 44}, + block_Left_Up: {start: 45, end: 54}, + block_Right_Down: {start: 126, end: 133}, + block_Left_Down: {start: 134, end: 146}, + stand_Left: {start: 55, end: 60}, + stand_Right: {start: 61, end: 67}, + jump_Right: {start: 68, end: 76 }, + jump_Left: {start: 77, end: 84 }, + crouch_Right_Down: {start: 85, end: 90}, + crouch_Right_Up: {start: 91, end: 94}, + crouch_Left_Down: {start: 95, end: 100}, + crouch_Left_Up: {start: 101, end: 104}, + walk_Right: {start: 146, end: 154}, + walk_Left: {start: 155, end: 162}, + kick_Right_Up: {start: 163, end: 167}, + kick_Left_Up: {start: 168, end: 172}, + }, + size: { + w: 224, + h: 214 + } + }, + bar_enemy_timing:{ + value: { + punch_Right: {start: 261, end: 276}, + punch_Left: {start: 15, end: 30}, + punch_Right_Down: {start: 181, end: 195, active: {start:192, end:195} }, + punch_Left_Down: {start: 167, end: 180, active: {start:176, end:179} }, + block_Right: {start: 254, end: 259, speed: 1}, + block_Left: {start: 248, end: 253, speed: 1}, + block_Right_Up: {start: 73, end: 85}, + block_Left_Up: {start: 49, end: 57}, + block_Right_Down: {start: 243, end: 247, speed: 1}, + block_Left_Down: {start: 238, end: 242, speed: 1}, + stand_Left: {start: 0, end: 6, speed: 1}, + stand_Right: {start: 7, end: 13, speed: 1}, + jump_Right: {start: 120, end: 131 }, + jump_Left: {start: 97, end: 108 }, + crouch_Right_Down: {start: 150, end: 165}, + crouch_Right_Up: {start: 162, end: 155}, + crouch_Left_Down: {start: 133, end: 148}, + crouch_Left_Up: {start: 145, end: 140}, + walk_Right: {start: 223, end: 237}, + walk_Left: {start: 208, end: 222}, + kick_Right_Up: {start: 203, end: 208}, + kick_Left_Up: {start: 197, end: 202} + }, + size: { + w: 148, + h: 214 + }, + speed: 2 + }, + car_salon_enemy_timing:{ + value: { + punch_Right: {start: 159, end: 166}, + punch_Left: {start: 8, end: 15}, + punch_Right_Down: {start: 64, end: 70}, + punch_Left_Down: {start: 134, end: 140}, + block_Right: {start: 0, end: 7}, + block_Left: {start: 39, end: 45}, + block_Right_Up: {start: 18, end: 22}, + block_Left_Up: {start: 26, end: 30}, + block_Right_Down: {start: 125, end: 133}, + block_Left_Down: {start: 149, end: 157}, + stand_Left: {start: 56, end: 63}, + stand_Right: {start: 47, end: 55}, + jump_Right: {start: 80, end: 86 }, + jump_Left: {start: 87, end: 93 }, + crouch_Right_Down: {start: 101, end: 107}, + crouch_Right_Up: {start: 106, end: 109}, + crouch_Left_Down: {start: 169, end: 172}, + crouch_Left_Up: {start: 173, end: 174}, + walk_Right: {start: 117, end: 124}, + walk_Left: {start: 141, end: 148}, + kick_Right_Up: {start: 109, end: 116}, + kick_Left_Up: {start: 93, end: 100}, + }, + size: { + // w: 224, + // h: 214 + } + }, + gg_cabinet_enemy_timing:{ + value: { + punch_Right: {start: 9, end: 17}, + punch_Left: {start: 0, end: 8}, + punch_Right_Down: {start: 124, end: 129}, + punch_Left_Down: {start: 118, end: 123}, + block_Right: {start: 26, end: 33}, + block_Left: {start: 18, end: 25}, + block_Right_Up: {start: 42, end: 49}, + block_Left_Up: {start: 34, end: 41}, + block_Right_Down: {start: 154, end: 161}, + block_Left_Down: {start: 130, end: 137}, + stand_Left: {start: 50, end: 57}, + stand_Right: {start: 58, end: 65}, + jump_Right: {start: 74, end: 81 }, + jump_Left: {start: 66, end: 73 }, + crouch_Right_Down: {start: 110, end: 114}, + crouch_Right_Up: {start: 115, end: 117}, + crouch_Left_Down: {start: 98, end: 104}, + crouch_Left_Up: {start: 105, end: 109}, + walk_Right: {start: 146, end: 153}, + walk_Left: {start: 138, end: 145}, + kick_Right_Up: {start: 90, end: 97}, + kick_Left_Up: {start: 82, end: 89}, + }, + size: { + // w: 224, + // h: 214 + } + } +} + +// reaction — ответная рекация бота на наши действия +// chance — вероятность того, что это действие будет выбрано ботом +// name — имя реакции, отсылающее к названию действия (метода классов Player и Enemy) +// damage — урон +// resist — уменьшение урона +// complex — сложное действие, состоящее из двух или более. У него нет параметров, +// оно просто отсылает к методу классов Player и Enemy +// start и end — номера кадров начала и конца анимации +// once — действие, выванное единожды за одно нажатие клавиши (если зажали кнопку и не отпускаем), +// например walk вызывается постоянно, пока зажата клавиша, а удар при зажатой клавише +// вызовется только один раз — чтобы вызвать его еще раз надо отпустить клавишу и снова нажать +// no_return — значит, мы не возвращаемся в стойку после действия once. Например, мы присели crouch +// active — активные кадры, когда персонаж способен наносить урон, если не указано, +// то активна середина анимации +// cool_down — число ударов, после которых наступит заморозка + +class FrameData{ + constructor(timing){ + this.timing = timing; + this.punch_Right = {once: true, start: undefined, end: undefined, + damage: 0.5, + reaction: [{name: "block", chance: "0-50"}, {name: "punch", chance: "50-80"}, {name: "stand", chance: "80-100"}] + }; + this.punch_Left = {once: true, start: undefined, end: undefined, + damage: 0.5, + reaction: [{name: "block", chance: "0-50"}, {name: "punch", chance: "50-80"}, {name: "stand", chance: "80-100"}] + }; + this.punch_Right_Down = {once: true, no_return: true, start: undefined, end: undefined, + damage: 0.5, + reaction: [{name: "block", chance: "0-50"}, {name: "punch", chance: "50-80"}, {name: "crouch", chance: "80-100"}] + }; + this.punch_Left_Down = {once: true, no_return: true, start: undefined, end: undefined, + damage: 0.5, + reaction: [{name: "block", chance: "0-50"}, {name: "punch", chance: "50-80"}, {name: "crouch", chance: "80-100"}] + }; + this.block_Right = { start: undefined, end: undefined, resist: 1, active: {start:20, end:24}, + reaction: [{name: "punch", chance: "00-80"}, {name: "stand", chance: "80-100"}] + }; + this.block_Left = { start: undefined, end: undefined, resist: 1 , active: {start:29, end:33}, + reaction: [{name: "punch", chance: "00-80"}, {name: "stand", chance: "80-100"}] + }; + this.block_Right_Up = { start: undefined, end: undefined, resist: 1, active: {start:39, end:42}, + reaction: [{name: "punch", chance: "00-80"}, {name: "stand", chance: "80-100"}] + }; + this.block_Left_Up = { start: undefined, end: undefined, resist: 1, active: {start:48, end:52}, + reaction: [{name: "punch", chance: "00-80"}, {name: "stand", chance: "80-100"}] + }; + this.block_Right_Down = { start: undefined, end: undefined, resist: 1, active: {start:39, end:42}, + reaction: [{name: "punch", chance: "00-80"}, {name: "stand", chance: "80-100"}] + }; + this.block_Left_Down = { start: undefined, end: undefined, resist: 1, active: {start:48, end:52}, + reaction: [{name: "punch", chance: "00-80"}, {name: "stand", chance: "80-100"}] + }; + this.stand_Left = { start: undefined, end: undefined, + reaction: [{name: "punch", chance: "0-60"}, {name: "kick", chance: "60-80"}, {name: "stand", chance: "80-90"}, {name: "walkAway", chance: "90-100"}] + }; + this.stand_Right = { start: undefined, end: undefined, + reaction: [{name: "punch", chance: "0-60"}, {name: "kick", chance: "60-80"}, {name: "stand", chance: "80-90"}, {name: "walkAway", chance: "90-100"}] + }; + this.jump_Right = { start: undefined, end: 76, + reaction: [{name: "jumpAsidePunch", chance: "0-50"}, {name: "stand", chance: "0-50"}] + }, + this.jump_Left = { start: undefined, end: 84, + reaction: [{name: "jumpAsidePunch", chance: "0-50"}, {name: "stand", chance: "0-50"}] + }, + this.crouch_Right_Down = {start: undefined, end: undefined, resist: 0.2, once: true , no_return: true, + reaction: [{name: "crouch", chance: "0-50"}, {name: "punch", chance: "50-100"}] + }; + this.crouch_Right_Up = { start: undefined, end: 94 , once: true , no_return: true, + reaction: [{name: "crouch", chance: "0-100"}] + }; + this.crouch_Left_Down = {start: undefined, end: undefined, resist: 0.2, once: true, no_return: true, + reaction: [{name: "crouch", chance: "0-50"}, {name: "punch", chance: "50-100"}] + }; + this.crouch_Left_Up = { start: undefined, end: 104 , once: true, no_return: true, + reaction: [{name: "crouch", chance: "0-100"}] + }; + this.walk_Right = { start: undefined, end: undefined, + reaction: [{name: "walk", chance: "0-50"}, {name: "jumpAsidePunch", chance: "50-60"}, {name: "stand", chance: "60-80"}, {name: "jumpAside", chance: "80-100"}] + }; + this.walk_Left = { start: undefined, end: undefined, + reaction: [{name: "walk", chance: "0-50"}, {name: "jumpAsidePunch", chance: "50-60"}, {name: "stand", chance: "60-80"}, {name: "jumpAside", chance: "80-100"}] + }; + this.kick_Right_Up = { start: undefined, end: undefined, once: true, damage: 1, cool_down: 4, + reaction: [{name: "block", chance: "0-50"}, {name: "punch", chance: "50-80"}, {name: "stand", chance: "80-100"}] + }; + this.kick_Left_Up = { start: undefined, end: undefined, once: true, damage: 1, cool_down: 4, + reaction: [{name: "block", chance: "0-50"}, {name: "punch", chance: "50-80"}, {name: "stand", chance: "80-100"}] + }; + this.jumpAside_Right = {}; + this.jumpAside_Left = {}; + this.jumpAsidePunch_Right = {}; + this.jumpAsidePunch_Left = {}; + this.walkAway_Right = {}; + this.walkAway_Left = {}; + } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..39c3af6 --- /dev/null +++ b/index.html @@ -0,0 +1,66 @@ + + + + + 2D Игра + + + +
+ + + +
+
+ + + + + + + + + \ No newline at end of file diff --git a/player.js b/player.js new file mode 100644 index 0000000..1146e1e --- /dev/null +++ b/player.js @@ -0,0 +1,647 @@ +class Player{ + constructor(w, h, image, dx, type, name, frameWidth = 224, frameHeight = 214, + frameSpeed = 1, size = 1){ + if(type == "bot"){ + this.direction = '_Left'; + } + else{ + this.direction = '_Right'; + } + this.size = size; + this.x = w / 10 + dx; + this.y = canvas.height - this.frameHeight / 2; + this.frameWidth = frameWidth; + this.frameHeight = frameHeight; + this.currentFrame = 0; + this.currentAction = "stand" + this.direction; + this.frameSpeed = frameSpeed; + this.speed = 30; + this.dx = 0; + this.dy = 0; + this.image = image; + this.stopped = false; // блокировка передвижения + this.stopCount = 0; // счетчик блокировки передвижения, по достижении нужного значения + // персонаж снова сможет передвигаться + this.nemesis = null; // противник + this.type = type; // тип персонажа: игрок или робот + this.name = name; + this.idleCount = 0; // счтечик бездействия + this.maxIdle = 60; + this.min_distance = 70; // минимальное значение дистанции коллизии + this.max_distance = 300; // максимальное значение дистанции коллизии + this.health = { + max: 100, + current: 100 + } + this.rage = { //Ярость + max: 100, + current: 0, + } + this.stunCount = 0; // оглушение, когда соперник бьет критом после накопления яорсти + this.coolDown = 0; // кулдаун на все действия после обычного действия, например, блока + this.coolDownArray = []; // массив кулдаунов конкретных ударов + } + collision(){ + if(this.type == "bot"){ + this.potential_nemesis = game.player; + } + else{ + this.potential_nemesis = game.characters.enemy; + } + + // бот всегда смотрит в сторону игрока + if(this.type == "bot" && this.potential_nemesis){ + if(this.potential_nemesis.x <= this.x){ + this.direction = "_Left"; + } + else{ + this.direction = "_Right"; + } + } + + if(this.potential_nemesis){ + this.collision_distance = Math.abs(this.potential_nemesis.x - this.x); + } + + // переходим в остояние боя, если дистанция меньше определенного значения + if(this.collision_distance <= this.min_distance){ + if(!this.potential_nemesis.dy && !this.dy){ // Если мы в прыжке, то коллизия не срабатывает + this.nemesis = this.potential_nemesis; + + if(this.stopCount >= 5){ + this.stopped = false; + } + else if(this.nemesis.stunCount == 0){ + if(!this.stopped){ + this.stopCount = 1; + } + this.stopped = true; + } + if(this.stopCount > 10){ + this.stopCount = 1; + } + if(this.stopCount > 0){ + this.stopCount++; + } + } + } + else if(this.nemesis){ // вышли из коллизии + this.nemesis = null; + this.stopped = false; + this.stopCount = 0; + } + if(this.collision_distance < this.max_distance){ + this.idleCount = 0; + } + if(this.collision_distance < this.max_distance || this.idleCount > this.maxIdle){ + + } + else{ + this.stopped = false; + this.stopCount = 0; + } + } + update(){ + if(!game.intro){ + this.idleCount++; + } + + if(this.type == "player"){ + const action = Object.keys(key_down)[Object.keys(key_down).length - 1]; + + if(action){ + // Вызываем действие, если кнопка нажата и действие еще не выполнено + // либо кнопка зажата и мы идем + // При этом предыдущее действие либо закончено (т.е. currentFrame == 0), + // либо мы стоим, прыгаем или присели (т.е. действия не once и не no_return) + if( (key_down[action] != false || action.split("_")[0] == "walk") + && (this.currentFrame == 0 + || !frame_data[this.name][this.currentAction].once + || (frame_data[this.name][this.currentAction].no_return + && + this.currentFrame >= frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1 + ) + ) + ){ + + if(action.split("_")[0] != "walk"){ + key_down[action] = false + } + + if( !( action.split("_")[0] == "walk" && this.currentAction == "walk" + this.direction ) ){ + // console.log(this.currentAction, this.currentFrame) + this.doAction(action); + } + } + } + + // Если идем, и нажата кнопка, лействие которой не jump и не walk + if( + key_down["walk" + this.direction] + && this.currentAction.split("_")[0] != "walk" + && this.currentAction.split("_")[0] != "jump" + + || + + this.currentAction == "walk" + this.direction + && !key_down[this.currentAction] + + ){ + this.dx = 0; + } + + } + + if(this.stunCount && this.stunCount <= 2){ + this.stunCount++; + const count = 5; // число шагов (чем выше, тем быстрее) + // Если противник кританул, нас отталкивает за дистанцию боя, + // то есть меняется dx, замедляясь к концу движения + if(this.nemesis && this.stunCount > 0 && this.stunCount < count){ + this.nemesis.stopped = false; + this.doAction('stand' + this.direction); + // косинус менятеся от 1 (при аргументе 0) до 0 (при аргументе Math.PI/2) + // this.stunCount изначальо будет равен 2, поэтому чтобы получить ноль, пишем this.stunCount-2 + // делим Math.PI / 2 на count и получаем число секторов, которые надо тпройти + // 27 — целое число, при умножении на которое при count = 5 получим целое число, ближайшее к 71 (дистанция боя) + // 71 = x * ( Math.cos( 0 * Math.PI / 2 / 5) + Math.cos( 1 * Math.PI / 2 / 5) + Math.cos( 2 * Math.PI / 2 / 5) ) + // x = 71 / 2.7 = 27 + this.nemesis.dx = 27 * directions[this.nemesis.direction] * -1 * Math.cos( (this.stunCount - 2) * Math.PI / 2 / count) + // console.log(this.nemesis.dx, this.stunCount) + } + + } + else{ + this.stunCount = 0; + } + + if(this.coolDown && this.coolDown <= 2){ + this.coolDown++; + } + else{ + this.coolDown = 0; + } + + this.collision(); + + const my_action_params = frame_data[this.name][this.currentAction]; + if(!game.over || game.info_animation_timer){ + if(this.rage.current > 0){ + if(!this.nemesis){ + this.rage.current -= 0.2; + } + else{ + this.rage.current -= 0.1; + } + } + else{ + this.rage.current = 0; + } + + if(this.nemesis){ + const nemesis_action_params = frame_data[this.nemesis.name][this.nemesis.currentAction]; + if(this.type == "bot"){ + if(this.nemesis.currentAction.split("_")[0] != "walk"){ + this.reaction(nemesis_action_params); + } + // если идем во время боя, то реакция как на действие stand + else{ + this.reaction(frame_data[this.name]["stand" + this.nemesis.direction]); + } + } + this.block(nemesis_action_params, my_action_params); + } + this.countFrameData(my_action_params); + } + this.draw(); + } + countFrameData(my_action_params){ + // game.player.rage.current = 100; + // Если анимаци продолжается, то есть номер кадра менбше разнициы end и start + var action = frame_data[this.name][this.currentAction]; + + if(action && this.currentFrame < frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1){ + if(frame_data[this.name][this.currentAction].speed){ + this.currentFrame = Math.round(this.currentFrame + + frame_data[this.name][this.currentAction].speed); + } + else{ + this.currentFrame = Math.round(this.currentFrame + this.frameSpeed); + } + // Если прыжок и нет верхнего удара + if(this.dy && this.currentAction.split("_")[0] != "kick" + && this.currentAction.split("_")[2] != "Up"){ + // узнаем номер кадра в прыжке делением текущего значения dy на восьмую часть максимального значения dy. + // 8 — число кадров в анимации прыжка + this.currentFrame = Math.ceil( this.dy / (Math.PI / 8) ); + } + + if(!this.stopped && this.x >= 0 && this.x <= canvas.width){ + this.x += this.dx; + if(this.x < 0){ + this.x = 0; + } + else if(this.x > canvas.width){ + this.x = canvas.width; + } + } + + if(this.type == "player"){ + // console.log(key_down["walk" + this.direction], "walk" + this.direction, this.currentAction) + } + } + // Если анимация завершилась + else{ + this.complex = false; + // Если отжата кнопка, + // то меняем действие на stand и обнуляем dx, на случай если персонаж шел + // if(this.type == "player"){ + // console.log(key_down[this.currentAction.split("_")[0]], this.currentAction.split("_")[0], this.currentAction) + // } + if(this.currentAction.split("_")[0] == "walk"){ + var current_action = this.currentAction; + } + else{ + var current_action = this.currentAction + this.direction; + } + + if(!key_down[current_action] || this.type == "bot"){ + if(this.type == "player"){ + // console.log("Отжата", current_action, key_down[current_action]) + } + if(this.type != "bot" && !arrow_down || this.type == "bot" && !this.crouch || + this.stunCount > 0){ + + if(this.type == "bot"){ + // console.log(this.currentFrame, this.currentAction, frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1) + } + // Встаем + this.doAction('stand' + this.direction); + if(this.type != "bot" && this.nemesis && this.nemesis.crouch){ + this.nemesis.crouch = false; + } + } + // Если не нажата кнопка вниз + else{ + // Продолжаем сидеть + this.currentAction = "crouch" + this.direction + "_Down"; + } + this.dx = 0; + } + // Иначе просто обнуляем currentFrame кадра и анимация начнется снова + else{ + if(!my_action_params.no_return + && this.currentAction.split("_")[0] != "walk"){ + key_down[this.currentAction] = false; + this.doAction('stand' + this.direction); + } + else if(!my_action_params.once){ + this.currentFrame = 0; + if(!this.stopped && this.x >= 0 && this.x <= canvas.width){ + this.x += this.dx; // добавляем для плавности перемещение в конце анимации walk + if(this.x < 0){ + this.x = 0; + } + else if(this.x > canvas.width){ + this.x = canvas.width; + } + } + } + } + } + // условие для прыжка + if(this.dy){ + // примем максимально значение dy за число пи + if(this.dy <= Math.PI){ + // косинус менятеся от 1 (при dy = 0) до 0 (при dy = Math.PI/2) и снова до 1 (при dy = Math.PI) + // Поэтому к середине прыжка скорость замедлится до 0 (5 * 0 = 0) + this.y -= 50 * Math.cos(this.dy); + this.dy += Math.PI / 8; + } + // прыжок закончился + if(this.dy > Math.PI){ + this.dy = 0; + this.dx = 0; + // key_down["walk" + this.direction] = false; + if(!game.info_animation_timer){ + this.y = canvas.height - this.frameHeight / 2; + } + else{ + this.y = 100; + } + this.doAction('stand' + this.direction); + this.currentFrame = 0; + } + } + // если прыжка нет, то персонаж всегда внизу экрана, даже если изменили размер окна + else{ + if(!game.info_animation_timer){ + this.y = canvas.height - this.frameHeight / 2; + } + else{ + this.y = 100; + } + } + } + block(nemesis_action_params, my_action_params){ + // Проверка на блок и пересчет здоровья + const [action_name, action_hor_direct, action_vert_direct] = this.currentAction.split("_"); + const [nemesis_action_name, nemesis_action_hor_direct, nemesis_action_vert_direct] = this.nemesis.currentAction.split("_"); + const condition = this.nemesis.currentFrame == Math.round((nemesis_action_params.end - nemesis_action_params.start) / 2); + const start = nemesis_action_params.start; + const condition2 = "active" in nemesis_action_params + && start + this.nemesis.currentFrame > nemesis_action_params.active.start + && start + this.nemesis.currentFrame < nemesis_action_params.active.end; + + // if(this.type == "player" && nemesis_action_params.active){ + // console.log(start + this.nemesis.currentFrame , nemesis_action_params.active.start + // , nemesis_action_params.active.end, start + this.nemesis.currentFrame > nemesis_action_params.active.start + // , start + this.nemesis.currentFrame < nemesis_action_params.active.end) + // } + + if("damage" in nemesis_action_params && + (nemesis_action_hor_direct == "Left" && this.nemesis.x > this.x || + nemesis_action_hor_direct == "Right" && this.nemesis.x < this.x) + && (condition || condition2) ){ + let resist = 0; + + // противодействие урону + const start2 = frame_data[this.name][this.currentAction].start; + const condition3 = "active" in frame_data[this.name][this.currentAction] + && start2 + this.currentFrame > frame_data[this.name][this.currentAction].active.start + && start2 + this.currentFrame < frame_data[this.name][this.currentAction].active.end; + + // if(this.type == "player"){ + // console.log() + // } + let damage = nemesis_action_params.damage * 3; + // Чем выше урон от противника, тем выше ярость + const rage_delta = 10 * damage; + if(condition3 && "resist" in my_action_params){ // если действие содержит resist + // проверяем разнонаправленность по горизонтали ("_Left", "_Right") + + if(action_hor_direct != nemesis_action_hor_direct){ + // проверяем совпадение направления по вертиакали ("Up", "Down", undefined) + if(action_vert_direct == nemesis_action_vert_direct){ + resist = my_action_params.resist; + this.nemesis.coolDown = 2; + } + } + else{ + this.rage.current += rage_delta; + } + this.stopCount += 25; + } + else{ + this.rage.current += rage_delta; + } + + if(this.rage.current > this.rage.max){ + this.rage.current = this.rage.max; + } + + if(this.nemesis.rage.current >= this.nemesis.rage.max * 0.9){ + damage *= 10; + this.nemesis.stunCount = 1; + if(this.type == "player"){ + this.nemesis.doAction("punch" + this.nemesis.direction); + } + this.nemesis.rage.current = 0; + } + + this.health.current -= damage - resist; + if(this.health.current <= 0){ + this.health.current = 0; + game.over = true; + if(this.type == "bot"){ + player_win++; + } + else{ + bot_win++; + } + round++; + game.checkWin(); + } + } + } + draw(){ + const key = frame_data[this.name][this.currentAction]; + if(key){ + const { start, end } = key; + ctx.drawImage(this.image, + (start + this.currentFrame) * this.frameWidth, 0, + this.frameWidth, this.frameHeight, + this.x - this.frameWidth / 2, this.y - this.frameHeight / 2, this.frameWidth * this.size, this.frameHeight * this.size); + } + } + // метод объединяет вызов анимации и метода действия (чтобы не вызывать анимацию в каждом действии отдельно) + doAction(action){ + if(this.type != "bot"){ + if(frame_data[this.name][action]){ + if("cool_down" in frame_data[this.name][action]){ + if(!this.coolDownArray[action]){ + this.coolDownArray[action] = 0; + } + if(action == this.currentAction){ + this.coolDownArray[action]++; + } + else{ + this.coolDownArray[action] = 0; + } + // console.log(this.coolDownArray[action], action, this.currentAction) + } + } + } + // frame_data[this.name][action].cool_down - 1 — отсчет от нуля, а ключ объекта от единицы + if(this.stunCount > 0 || this.coolDown > 0 + || frame_data[this.name][action] + && frame_data[this.name][action].cool_down + && this.coolDownArray[action] + && this.coolDownArray[action] >= frame_data[this.name][action].cool_down - 1 ){ + + if(this.coolDownArray[action] >= frame_data[this.name][action].cool_down - 1){ + this.coolDownArray[action] = 0; + this.stunCount = 1; + } + + // перезаписываем action + action = "stand" + this.direction; + } + if(!this.dy){ // производим удар, только если мы не в прыжке + // Сложные действия, состоящие из нескольких, вернут флаг true. + let complicated_action_flag; + if(this[action]){ + complicated_action_flag = this[action](action); // вызываем конкретный метод действия или удара + } + else{ + console.log("Нет такого действия " + action + " в объекте frame_data[this.name]") + } + + // Без этого флага будет пытаться названчить в this.currentAction несуществующее действие + if(frame_data[this.name][action] && !complicated_action_flag){ + this.currentAction = action; // это в том числе идентификатор для анимации + } + } + // если в прыжке, то выполняются только верхние удары (все верхние удары называются kick) + else{ + if(action.split("_")[0] == "kick" && action.split("_")[2] == "Up"){ + this.currentAction = action; + } + } + this.currentFrame = 0; + } + jumpAside_Right(){ + this.doAction("walk_Right"); + this.doAction("jump_Right"); + return true; + } + jumpAside_Left(){ + this.doAction("walk_Left"); + this.doAction("jump_Left"); + return true; + } + jumpAsidePunch_Right(){ + this.doAction("walk_Right"); + this.doAction("jump_Right"); + let context = this; + setTimeout(function(){ + context.complex = true; + context.direction = "_Right" + context.doAction("kick_Right_Up") + console.log(context.currentAction, context.direction) + } , 100); + return true; + } + jumpAsidePunch_Left(){ + this.doAction("walk_Left"); + this.doAction("jump_Left"); + let context = this; + setTimeout(function(){ + context.complex = true; + context.direction = "_Left" + context.doAction("kick_Left_Up") + } , 100); + return true; + } + walkAway_Left(){ + if(!this.crouch){ + this.doAction("walk_Right"); + return true; + } + } + walkAway_Right(){ + if(!this.crouch){ + this.doAction("walk_Left"); + return true; + } + } + walk_Left(){ + if(!this.stopped){ + this.dx = -this.speed; + } + this.direction = '_Left'; + } + walk_Right(){ + if(!this.stopped){ + this.dx = this.speed; + } + this.direction = '_Right'; + } + punch_Right(){ + + } + punch_Left(){ + + } + punch_Right_Down(){ + + } + punch_Left_Down(){ + + } + block_Right(){ + + } + block_Left(){ + + } + block_Right_Up(){ + + } + block_Left_Up(){ + + } + block_Right_Down(){ + + } + block_Left_Down(action){ + // if(this.currentAction != "crouch_Left"){ + // this.doAction("crouch_Left"); + // // let context = this; + // // setTimeout(function(){ + // // // context.complex = true; + // // context.doAction("punch_Left") + // // } , 100); + // } + // // else{ + // // this.currentAction = action; + // // } + // return true; + } + jump_Right(){ + this.dy = 0.1; + } + jump_Left(){ + this.dy = 0.1; + } + crouch_Right_Down(){ + if(this.type == "bot"){ + this.crouch = true; + } + } + crouch_Left_Down(){ + if(this.type == "bot"){ + this.crouch = true; + } + } + crouch_Right_Up(){ + if(this.type == "bot"){ + this.crouch = false; + } + } + crouch_Left_Up(){ + if(this.type == "bot"){ + this.crouch = false; + } + } + kick_Right_Up(){ + + } + kick_Left_Up(){ + + } + stand_Left(action){ + if(this.currentAction == "crouch_Left_Down"){ + this.currentAction = "crouch_Left_Up"; + } + else{ + this.currentAction = action; + } + return true; + } + stand_Right(action){ + if(this.currentAction == "crouch_Right_Down"){ + this.currentAction = "crouch_Right_Up"; + } + else{ + this.currentAction = action; + } + return true; + } + test_Left(){ + console.log("Left_________________________"); + } + test_Right(){ + console.log("Right_________________________"); + } +} \ No newline at end of file diff --git a/typing.js b/typing.js new file mode 100644 index 0000000..7b1ccb6 --- /dev/null +++ b/typing.js @@ -0,0 +1,39 @@ + + +function type(ctx_name, mystring, x0, y0, size, align, input_width, input_height){ + var newline = 0; + var outdent = 0; + texgo = letters["a"]; + + if(align == "center"){ + var cell_size = Math.floor(size / texgo.length); + x0 = x0 + input_width / 2 - mystring.length * ((texgo[0].length + 1) * cell_size ) / 2; + y0 = y0 + input_height / 2- ((texgo.length + 1) * cell_size ) / 2; + } + else{ + var cell_size = size; + } + + // ctx_name.clearRect(x0, y0, x0 + mystring.length * ((texgo[0].length + 1) * cell_size ), y0 + texgo.length * cell_size); + for (var i = 0; i < mystring.length; i++){ + + if (mystring[i] == "&"){ + newline+= 8 + 4; + outdent = 0; + } + else{ + texgo = letters[mystring[i]]; + if(texgo){ + for (var x = 0; x < texgo.length; x++){ + for (var y = 0; y <= texgo[0].length; y++){ + if (texgo[x][y] == 1){ + ctx_name.fillStyle = "white"; + ctx_name.fillRect(x0 + (y + (texgo[0].length + 1) *outdent)*cell_size, y0 + (newline + x)*cell_size, cell_size, cell_size); + } + } + } + } + outdent++; + } + } +} \ No newline at end of file diff --git a/ui_panel.js b/ui_panel.js new file mode 100644 index 0000000..ff91116 --- /dev/null +++ b/ui_panel.js @@ -0,0 +1,168 @@ + +class UI{ + drawUserInfo(x, y, size, avatar, persone, name, n) { + const ratio = avatar.width / avatar.height; + const avatar_w = size / 2.5; + const avatar_h = avatar_w * ratio; + + var j = 10, j2 = 5, outdent_x1, outdent_x2; + if(n > 0){ + outdent_x1 = 0 - j; + outdent_x2 = avatar_w - j; + } + else{ + outdent_x1 = -(avatar_w - 20 - j2); + outdent_x2 = avatar_w - 20 + j2; + } + + ctx.fillStyle = "rgba(28, 128, 128, 0.7)"; + ctx.fillRect(x + outdent_x1, y - 40, size + outdent_x2, y + 17 + 10) + + ctx.fillStyle = "#FFFFFF"; + ctx.font = "25px Arial "; + ctx.textAlign = "center"; + ctx.fillText(name, x + size / 2, y - 10); + + ctx.drawImage(avatar, x + n, 10, avatar_h, avatar_w); + + var rage; + if(persone.rage.current >= persone.rage.max * 0.9){ + ctx.drawImage(images[persone.type + "_avatar_rage"], x + n, 10, avatar_h, avatar_w); + rage = size; + } + else{ + rage = size / persone.rage.max * persone.rage.current; + } + + ctx.fillStyle = "FireBrick"; + ctx.fillRect(x, y + 5, size / persone.health.max * persone.health.current, 10); + ctx.fillStyle = "DarkOrange"; + ctx.fillRect(x, y + 17, rage, 10); + + // if(persone.stopped || persone.stunCount > 0){ + // ctx.drawImage(images.lock, x + n + outdent_x1 + 55, 10, 20, 20); + // } + // if(persone.nemesis && persone.nemesis.coolDown > 0 || persone.block_ind){ + // if(!persone.block_ind){ + // setTimeout(function(){ + // persone.block_ind = false; + // }, 200, persone) + // } + // persone.block_ind = true; + // ctx.drawImage(images.block, x + n + outdent_x1 + 55, y + 17 + 10, 20, 20); + // } + + game.time_bar.caption = "Time left: " + String( game.round_time - game.seconds ); + + } + drawStartScreen(pers_image, bot_image, text_image, n, delay){ + this.clearAll(); + intro_ctx.beginPath(); + intro_ctx.moveTo(canvas.width - n, canvas.height); + intro_ctx.lineTo(0 - n, canvas.height); + intro_ctx.lineTo(canvas.width - n, 0); + intro_ctx.closePath(); + intro_ctx.fill(); + intro_ctx.globalCompositeOperation="source-out"; + this.drawStartImage(intro_ctx, pers_image, -n - 1); + intro_ctx.globalCompositeOperation="source-over"; + this.drawStartImage(intro_ctx, bot_image, n + 1); + } + drawStartImage(ctx, image, n){ + if(n > 0){ + var x0 = canvas.width - image.width * 1.5; + } + else{ + var x0 = 0; + } + ctx.drawImage(image, + x0 + n, 0, + image.width * 1.5, image.height * 1.5); + } + drawGameCaption(ctx, image, mask, n){ + const scale = 1.5; + + ctx.drawImage(image, + canvas.width / 2 - image.width / 2 / scale, + canvas.height / 2 - image.height / 2 / scale, + image.width / scale, image.height / scale); + + if(mask){ + ctx.globalCompositeOperation="source-out"; + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, canvas.width, canvas.height) + ctx.beginPath(); + ctx.moveTo(n * 2, canvas.height / 2 - 50); + ctx.lineTo(n * 2 + 20, canvas.height / 2 + 50); + ctx.lineTo(n * 2 + 30, canvas.height / 2 + 50); + ctx.lineTo(n * 2 + 20, canvas.height / 2 - 50); + ctx.moveTo(n * 2, canvas.height / 2 - 50); + ctx.closePath(); + ctx.fill(); + } + else{ + ctx.globalCompositeOperation="source-over"; + } + } + clearAll(){ + intro_ctx.clearRect(0,0,canvas.width,canvas.height); + text_ctx.clearRect(0,0,canvas.width,canvas.height); + } + drawTimeBar(ctx, image, mask, n, scale){ + ctx.drawImage(image, + canvas.width / 2 - image.width / 2 * scale, + canvas.height / 2 - image.height / 2 * scale, + image.width * scale, image.height * scale); + + if(mask){ + ctx.globalCompositeOperation="source-out"; + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, canvas.width, canvas.height) + ctx.fillStyle = "red"; + ctx.fillRect(0, 0, canvas.width, canvas.height) + } + else{ + ctx.globalCompositeOperation="source-over"; + } + } +} +class Square{ + constructor(ctx_name, x, y, width, height, background, value) { + this.ctx = ctx_name; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.background = background; + this.value = value; + this.v; + this.cap; + } + set value(value){ + this.v = value; + } + get value(){ + return this.v; + } + set background(background){ + if (background == "" || background == undefined){ + // ctx.clearRect(this.x * this.width, this.y * this.height, this.width, this.height); + } + else{ + ctx.fillStyle = background; + ctx.beginPath(); + ctx.roundRect(this.x * this.width, this.y * this.height, this.width, this.height, [10]); + ctx.fill(); + } + + } +} +class Button extends Square { + set caption(caption){ + this.cap = caption; + type(ctx, caption, this.x * this.width, this.y * this.height, this.height / 2, "center", this.width, this.height); + } + get caption(){ + return this.cap; + } +} \ No newline at end of file