fighting/battle.js
2025-08-16 10:24:23 +00:00

704 lines
29 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/////////////////////
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;
}
}
}
});
}