You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1734 lines
49 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

class Cphoto {
constructor(root){
this.root = root;
this.$cphoto = $(`<div style="background-color: black; color: white; padding: 20px;width: 100%; height:100%;z-index : 9999"></div>`);
//this.hide();
//this.root.$ac_game.append(this.$cphoto);
this.start();
}
start(){
}
hide(){
this.$cphoto.hide();
}
show(){
this.$cphoto.show();
}
}
class AcGameMenu {
constructor(root) {
this.root = root;
this.$menu = $(`
<div class="ac-game-menu">
<div class="ac-game-menu-field">
<div class="ac-game-menu-field-item ac-game-menu-field-item-cphoto">
头像选择
</div>
<div class="ac-game-menu-field-item ac-game-menu-field-item-single-mode">
单人模式
</div>
<br>
<div class="ac-game-menu-field-item ac-game-menu-field-item-multi-mode">
多人模式
</div>
<div class="ac-game-menu-field-item ac-game-menu-field-item-ranklist">
天梯榜
</div>
<br>
<div class="ac-game-menu-field-item ac-game-menu-field-item-settings">
退出
</div>
</div>
</div>
`);
this.$menu.hide();
this.root.$ac_game.append(this.$menu);
this.$single_mode = this.$menu.find('.ac-game-menu-field-item-single-mode');
this.$multi_mode = this.$menu.find('.ac-game-menu-field-item-multi-mode');
this.$settings = this.$menu.find('.ac-game-menu-field-item-settings');
this.$cphoto_button = this.$menu.find('.ac-game-menu-field-item-cphoto');
this.$ranklist_button = this.$menu.find('.ac-game-menu-field-item-ranklist')
this.start();
}
start() {
this.add_listening_events();
}
add_listening_events() {
let outer = this;
this.$single_mode.click(function () {
outer.hide();
outer.root.playground.show("single mode");
});
this.$multi_mode.click(function () {
outer.hide();
outer.root.playground.show("multi mode");
});
this.$settings.click(function () {
outer.root.settings.logout_on_remote();
});
this.$cphoto_button.click(function () {
window.location.href = '/photo';
console.log(outer.root.settings.photo);
});
this.$ranklist_button.click(function () {
$.ajax({
url: "https://app6641.acapp.acwing.com.cn/settings/ranklist/",
type: "GET",
headers: {
'Authorization': "Bearer " + outer.root.access,
},
success: function (resp) {
// 清空当前页面内容
document.body.innerHTML = `
<div style="text-align: center; margin-top: 20px;">
<button id="logout-button" style="
padding: 10px 20px;
background-color: #f44336;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin-bottom: 20px;
">退出</button>
<h1>用户排名</h1>
</div>
<table style="
width: 60%;
margin: auto;
border-collapse: collapse;
">
<thead>
<tr>
<th style="
padding: 10px;
border: 1px solid #ddd;
text-align: center;
">排名</th>
<th style="
padding: 10px;
border: 1px solid #ddd;
text-align: center;
">头像</th>
<th style="
padding: 10px;
border: 1px solid #ddd;
text-align: center;
">用户名</th>
<th style="
padding: 10px;
border: 1px solid #ddd;
text-align: center;
">分数</th>
</tr>
</thead>
<tbody id="ranklist-body">
<!-- 用户排名信息将通过 JavaScript 插入到这里 -->
</tbody>
</table>
`;
// 获取表格主体的 DOM 元素
const ranklistBody = document.getElementById('ranklist-body');
// 遍历用户数据并生成 HTML 行
resp.forEach((user, index) => {
const row = document.createElement('tr');
// 排名
const rankCell = document.createElement('td');
rankCell.textContent = index + 1;
rankCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
row.appendChild(rankCell);
// 头像
const photoCell = document.createElement('td');
const img = document.createElement('img');
img.src = user.photo;
img.alt = user.username;
img.setAttribute("style", "width: 50px; height: 50px; border-radius: 50%;");
photoCell.appendChild(img);
photoCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
row.appendChild(photoCell);
// 用户名
const usernameCell = document.createElement('td');
usernameCell.textContent = user.username;
usernameCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
row.appendChild(usernameCell);
// 分数
const scoreCell = document.createElement('td');
scoreCell.textContent = user.score;
scoreCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
row.appendChild(scoreCell);
// 将行添加到表格主体中
ranklistBody.appendChild(row);
});
// 添加“退出”按钮点击事件
document.getElementById('logout-button').addEventListener('click', () => {
window.location.href = "https://app6641.acapp.acwing.com.cn/"; // 将此路径替换为实际的注销页面路径
});
},
error: function (xhr, status, error) {
console.error("请求失败:", error);
alert("无法获取排名列表,请稍后重试。");
}
});
});
}
show() {
this.$menu.show();
}
hide() {
this.$menu.hide();
}
}
let AC_GAME_OBJECTS = [];
class AcGameObject {
constructor() {
AC_GAME_OBJECTS.push(this);
this.has_called_start = false; // 是否执行过start函数
this.timedelta = 0; // 当前帧距离上一帧的时间间隔
this.uuid = this.create_uuid();
}
create_uuid() {
let res = "";
for(let i = 0;i < 8 ; i++){
let x = parseInt(Math.floor(Math.random()*10));
res += x;
}
return res;
}
start() { // 只会在第一帧执行一次
}
update() { // 每一帧均会执行一次
}
late_update(){
}
on_destroy() { // 在被销毁前执行一次
}
destroy() { // 删掉该物体
this.on_destroy();
for (let i = 0; i < AC_GAME_OBJECTS.length; i ++ ) {
if (AC_GAME_OBJECTS[i] === this) {
AC_GAME_OBJECTS.splice(i, 1);
break;
}
}
}
}
let last_timestamp;
let AC_GAME_ANIMATION = function(timestamp) {
for (let i = 0; i < AC_GAME_OBJECTS.length; i ++ ) {
let obj = AC_GAME_OBJECTS[i];
if (!obj.has_called_start) {
obj.start();
obj.has_called_start = true;
} else {
obj.timedelta = timestamp - last_timestamp;
obj.update();
}
}
for(let i = 0;i< AC_GAME_OBJECTS.length;i++){
let obj = AC_GAME_OBJECTS[i];
obj.late_update();
}
last_timestamp = timestamp;
requestAnimationFrame(AC_GAME_ANIMATION);
}
requestAnimationFrame(AC_GAME_ANIMATION);
class ChatField{
constructor(playground){
console.log("chat");
this.playground = playground;
this.$history = $(`<div class = "ac-game-chat-field-history"></div>`)
this.$input = $(`<input type="text" class = "ac-game-chat-field-input">`)
this.$history.hide();
this.$input.hide();
this.playground.$playground.append(this.$history);
this.playground.$playground.append(this.$input);
this.start();
this.function_id = null;
}
start(){
this.add_listening_events();
}
add_listening_events(){
let outer =this;
this.$input.keydown(function(e){
if(e.which === 27){
outer.hide_input();
return false;
}else if (e.which === 13){
let username = outer.playground.root.settings.username;
let text = outer.$input.val();
if(text){
outer.$input.val("");
outer.add_message(username,text);
outer.playground.mps.send_message(text);
}
return false;
}
});
}
show_history(){
let outer = this;
this.$history.fadeIn();
if(this.function_id){
clearTimeout(this.function_id);
}
this.function_id = setTimeout(function(){
outer.$history.fadeOut();
outer.function_id = null;
},3000);
}
show_input(){
this.show_history();
this.$input.show();
this.$input.focus();
}
hide_input(){
this.$input.hide();
this.playground.game_map.$canvas.focus();
}
add_message(username,text){
this.show_history();
let message = `[${username}]${text}`
this.$history.append(this.render_message(message));
this.$history.scrollTop(this.$history[0].scrollHeight);
}
render_message(message){
return $(`<div>${message}</div>`);
}
}
class GameMap extends AcGameObject{
constructor(playground){
super();
this.playground=playground;
this.$canvas = $(`<canvas tabindex = 0></canvas>`);
this.ctx = this.$canvas[0].getContext('2d');
this.ctx.canvas.width = this.playground.width;
this.ctx.canvas.height = this.playground.height;
this.playground.$playground.append(this.$canvas);
}
start(){
this.$canvas.focus();
}
resize(){
this.ctx.canvas.width = this.playground.width;
this.ctx.canvas.height = this.playground.height;
this.ctx.fillStyle = "rgba(0,0,0)";
this.ctx.fillRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
}
update(){
this.render();
}
render(){
this.ctx.fillStyle = "rgba(0,0,0,0.2)";
this.ctx.fillRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
}
}
class NoticeBoard extends AcGameObject {
constructor(playground) {
super();
this.playground = playground;
this.ctx = this.playground.game_map.ctx;
this.text = "已就绪0人";
}
start() {
}
write(text) {
this.text = text;
}
update() {
this.render();
}
render() {
this.ctx.font = "20px serif";
this.ctx.fillStyle = "white";
this.ctx.textAlign = "center";
this.ctx.fillText(this.text, this.playground.width / 2, 20);
}
}
class Particle extends AcGameObject{
constructor(playground,x,y,radius,vx,vy,color,speed,move_length){
super();
this.playground = playground;
this.x = x;
this.y = y;
this.radius = radius;
this.vx= vx;
this.vy = vy;
this.color = color;
this.speed = speed;
this.ctx = this.playground.game_map.ctx;
this.fraction = 0.9;
this.eps = 0.01;
this.move_length = move_length;
}
start(){
}
update(){
if(this.move_length< this.eps||this.speed< this.eps){
this.destroy();
return false;
}
let moved = Math.min(this.move_length,this.speed*this.timedelta/1000);
this.x += this.vx*moved;
this.y += this.vy*moved;
this.speed *= this.fraction;
this.move_length -= moved;
this.render();
}
render(){
let scale = this.playground.scale;
this.ctx.beginPath();
this.ctx.arc(this.x * scale,this.y * scale,this.radius * scale,0,Math.PI * 2,false);
this.ctx.fillStyle = this.color;
this.ctx.fill();
}
}
class Player extends AcGameObject {
constructor(playground, x, y, radius, color, speed, character, username, photo) {
super();
this.playground = playground;
this.ctx = this.playground.game_map.ctx;
this.x = x;
this.y = y;
this.vx = 0;
this.vy = 0;
this.damage_x = 0;
this.damage_y = 0;
this.damage_speed = 0;
this.move_length = 0;
this.radius = radius;
this.color = color;
this.speed = speed;
this.character = character;
this.username = username;
this.photo = photo;
this.eps = 0.01;
this.friction = 0.9;
this.spent_time = 0;
this.fireballs = [];
this.cur_skill = null;
if (this.character !== "robot") {
this.img = new Image();
this.img.src = this.photo;
}
if (this.character === "me") {
this.fireball_coldtime = 3; // 单位:秒
this.fireball_img = new Image();
this.fireball_img.src = "https://cdn.acwing.com/media/article/image/2021/12/02/1_9340c86053-fireball.png";
this.blink_coldtime = 5; // 单位:秒
this.blink_img = new Image();
this.blink_img.src = "https://cdn.acwing.com/media/article/image/2021/12/02/1_daccabdc53-blink.png";
}
}
start() {
this.playground.player_count ++ ;
console.log(this.playground.player_count);
this.playground.notice_board.write("匹配中");
if (this.playground.player_count >= 3) {
this.playground.state = "fighting";
this.playground.notice_board.write("Fighting");
}
if (this.character === "me") {
this.add_listening_events();
} else if (this.character === "robot") {
let tx = Math.random() * this.playground.width / this.playground.scale;
let ty = Math.random() * this.playground.height / this.playground.scale;
this.move_to(tx, ty);
}
}
add_listening_events() {
let outer = this;
this.playground.game_map.$canvas.on("contextmenu", function() {
return false;
});
this.playground.game_map.$canvas.mousedown(function(e) {
if (outer.playground.state !== "fighting")
return true;
const rect = outer.ctx.canvas.getBoundingClientRect();
if (e.which === 3) {
let tx = (e.clientX - rect.left) / outer.playground.scale;
let ty = (e.clientY - rect.top) / outer.playground.scale;
outer.move_to(tx, ty);
if (outer.playground.mode === "multi mode") {
outer.playground.mps.send_move_to(tx, ty);
}
} else if (e.which === 1) {
let tx = (e.clientX - rect.left) / outer.playground.scale;
let ty = (e.clientY - rect.top) / outer.playground.scale;
if (outer.cur_skill === "fireball") {
if (outer.fireball_coldtime > outer.eps)
return false;
let fireball = outer.shoot_fireball(tx, ty);
if (outer.playground.mode === "multi mode") {
outer.playground.mps.send_shoot_fireball(tx, ty, fireball.uuid);
}
} else if (outer.cur_skill === "blink") {
if (outer.blink_coldtime > outer.eps)
return false;
outer.blink(tx, ty);
if (outer.playground.mode === "multi mode") {
outer.playground.mps.send_blink(tx, ty);
}
}
outer.cur_skill = null;
}
});
this.playground.game_map.$canvas.keydown(function(e) {
console.log(e.which);
if(e.which === 13){
if(outer.playground.mode === "multi mode")
outer.playground.chat_field.show_input();//打开了聊天框
} else if (e.which === 27){
if(outer.playground.mode === "multi mode"){
outer.playground.chat_field.hide_input();
}
}
if (outer.playground.state !== "fighting")
return true;
if (e.which === 81) { // q
if (outer.fireball_coldtime > outer.eps)
return true;
outer.cur_skill = "fireball";
return false;
} else if (e.which === 70) { // f
if (outer.blink_coldtime > outer.eps)
return true;
outer.cur_skill = "blink";
return false;
}
});
}
shoot_fireball(tx, ty) {
let x = this.x, y = this.y;
let radius = 0.01;
let angle = Math.atan2(ty - this.y, tx - this.x);
let vx = Math.cos(angle), vy = Math.sin(angle);
let color = "orange";
let speed = 0.5;
let move_length = 1;
let fireball = new FireBall(this.playground, this, x, y, radius, vx, vy, color, speed, move_length, 0.01);
this.fireballs.push(fireball);
this.fireball_coldtime = 3;
return fireball;
}
destroy_fireball(uuid) {
for (let i = 0; i < this.fireballs.length; i ++ ) {
let fireball = this.fireballs[i];
if (fireball.uuid === uuid) {
fireball.destroy();
break;
}
}
}
blink(tx, ty) {
let d = this.get_dist(this.x, this.y, tx, ty);
d = Math.min(d, 0.8);
let angle = Math.atan2(ty - this.y, tx - this.x);
this.x += d * Math.cos(angle);
this.y += d * Math.sin(angle);
this.blink_coldtime = 5;
this.move_length = 0; // 闪现完停下来
}
get_dist(x1, y1, x2, y2) {
let dx = x1 - x2;
let dy = y1 - y2;
return Math.sqrt(dx * dx + dy * dy);
}
move_to(tx, ty) {
this.move_length = this.get_dist(this.x, this.y, tx, ty);
let angle = Math.atan2(ty - this.y, tx - this.x);
this.vx = Math.cos(angle);
this.vy = Math.sin(angle);
}
is_attacked(angle, damage) {
for (let i = 0; i < 20 + Math.random() * 10; i ++ ) {
let x = this.x, y = this.y;
let radius = this.radius * Math.random() * 0.1;
let angle = Math.PI * 2 * Math.random();
let vx = Math.cos(angle), vy = Math.sin(angle);
let color = this.color;
let speed = this.speed * 10;
let move_length = this.radius * Math.random() * 5;
new Particle(this.playground, x, y, radius, vx, vy, color, speed, move_length);
}
this.radius -= damage;
if (this.radius < this.eps) {
this.destroy();
return false;
}
this.damage_x = Math.cos(angle);
this.damage_y = Math.sin(angle);
this.damage_speed = damage * 100;
this.speed *= 0.8;
}
receive_attack(x, y, angle, damage, ball_uuid, attacker) {
attacker.destroy_fireball(ball_uuid);
this.x = x;
this.y = y;
this.is_attacked(angle, damage);
}
update() {
this.spent_time += this.timedelta / 1000;
this.update_win();
if (this.character === "me" && this.playground.state === "fighting") {
this.update_coldtime();
}
this.update_move();
this.render();
}
update_win(){
if(this.playground.state === "fighting" && this.character === "me" && this.playground.players.length === 1){
this.state = "over";
this.playground.score_board.win();
}
}
update_coldtime() {
this.fireball_coldtime -= this.timedelta / 1000;
this.fireball_coldtime = Math.max(this.fireball_coldtime, 0);
this.blink_coldtime -= this.timedelta / 1000;
this.blink_coldtime = Math.max(this.blink_coldtime, 0);
}
update_move() { // 更新玩家移动
if (this.character === "robot" && this.spent_time > 4 && Math.random() < 1 / 300.0) {
let player = this.playground.players[Math.floor(Math.random() * this.playground.players.length)];
let tx = player.x + player.speed * this.vx * this.timedelta / 1000 * 0.3;
let ty = player.y + player.speed * this.vy * this.timedelta / 1000 * 0.3;
this.shoot_fireball(tx, ty);
}
if (this.damage_speed > this.eps) {
this.vx = this.vy = 0;
this.move_length = 0;
this.x += this.damage_x * this.damage_speed * this.timedelta / 1000;
this.y += this.damage_y * this.damage_speed * this.timedelta / 1000;
this.damage_speed *= this.friction;
} else {
if (this.move_length < this.eps) {
this.move_length = 0;
this.vx = this.vy = 0;
if (this.character === "robot") {
let tx = Math.random() * this.playground.width / this.playground.scale;
let ty = Math.random() * this.playground.height / this.playground.scale;
this.move_to(tx, ty);
}
} else {
let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000);
this.x += this.vx * moved;
this.y += this.vy * moved;
this.move_length -= moved;
}
}
}
render() {
let scale = this.playground.scale;
if (this.character !== "robot") {
this.ctx.save();
this.ctx.beginPath();
this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);
this.ctx.stroke();
this.ctx.clip();
this.ctx.drawImage(this.img, (this.x - this.radius) * scale, (this.y - this.radius) * scale, this.radius * 2 * scale, this.radius * 2 * scale);
this.ctx.restore();
} else {
this.ctx.beginPath();
this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);
this.ctx.fillStyle = this.color;
this.ctx.fill();
}
if (this.character === "me" && this.playground.state === "fighting") {
this.render_skill_coldtime();
}
}
render_skill_coldtime() {
let scale = this.playground.scale;
let x = 1.5, y = 0.9, r = 0.04;
this.ctx.save();
this.ctx.beginPath();
this.ctx.arc(x * scale, y * scale, r * scale, 0, Math.PI * 2, false);
this.ctx.stroke();
this.ctx.clip();
this.ctx.drawImage(this.fireball_img, (x - r) * scale, (y - r) * scale, r * 2 * scale, r * 2 * scale);
this.ctx.restore();
if (this.fireball_coldtime > 0) {
this.ctx.beginPath();
this.ctx.moveTo(x * scale, y * scale);
this.ctx.arc(x * scale, y * scale, r * scale, 0 - Math.PI / 2, Math.PI * 2 * (1 - this.fireball_coldtime / 3) - Math.PI / 2, true);
this.ctx.lineTo(x * scale, y * scale);
this.ctx.fillStyle = "rgba(0, 0, 255, 0.6)";
this.ctx.fill();
}
x = 1.62, y = 0.9, r = 0.04;
this.ctx.save();
this.ctx.beginPath();
this.ctx.arc(x * scale, y * scale, r * scale, 0, Math.PI * 2, false);
this.ctx.stroke();
this.ctx.clip();
this.ctx.drawImage(this.blink_img, (x - r) * scale, (y - r) * scale, r * 2 * scale, r * 2 * scale);
this.ctx.restore();
if (this.blink_coldtime > 0) {
this.ctx.beginPath();
this.ctx.moveTo(x * scale, y * scale);
this.ctx.arc(x * scale, y * scale, r * scale, 0 - Math.PI / 2, Math.PI * 2 * (1 - this.blink_coldtime / 5) - Math.PI / 2, true);
this.ctx.lineTo(x * scale, y * scale);
this.ctx.fillStyle = "rgba(0, 0, 255, 0.6)";
this.ctx.fill();
}
}
on_destroy() {
if (this.character === "me"){
if(this.playground.state === "fighting"){
this.playground.state = "over";
this.playground.score_board.lose();
}
}
for (let i = 0; i < this.playground.players.length; i ++ ) {
if (this.playground.players[i] === this) {
this.playground.players.splice(i, 1);
break;
}
}
}
}
class ScoreBoard extends AcGameObject {
constructor(playground) {
super();
this.playground = playground;
this.ctx = this.playground.game_map.ctx;
this.state = null; // win: 胜利lose失败
this.win_img = new Image();
this.win_img.src = "https://cdn.acwing.com/media/article/image/2021/12/17/1_8f58341a5e-win.png";
this.lose_img = new Image();
this.lose_img.src = "https://cdn.acwing.com/media/article/image/2021/12/17/1_9254b5f95e-lose.png";
}
start() {
}
add_listening_events() {
let outer = this;
if(this.playground.game_map === null)
return;
let $canvas = this.playground.game_map.$canvas;
$canvas.on('click', function() {
outer.playground.hide();
outer.playground.root.menu.show();
});
}
win() {
this.state = "win";
let outer = this;
setTimeout(function() {
outer.add_listening_events();
}, 1000);
}
lose() {
this.state = "lose";
let outer = this;
setTimeout(function() {
outer.add_listening_events();
}, 1000);
}
late_update() {
this.render();
}
render() {
let len = this.playground.height / 2;
if (this.state === "win") {
this.ctx.drawImage(this.win_img, this.playground.width / 2 - len / 2, this.playground.height / 2 - len / 2, len, len);
} else if (this.state === "lose") {
this.ctx.drawImage(this.lose_img, this.playground.width / 2 - len / 2, this.playground.height / 2 - len / 2, len, len);
}
}
}
class FireBall extends AcGameObject {
constructor(playground,player,x,y,radius,vx,vy,color,speed,move_length,damage){
super();
this.playground=playground;
this.ctx = this.playground.game_map.ctx;
this.player = player;
this.x = x;
this.y = y;
this.radius = radius;
this.vx = vx;
this.vy = vy;
this.color = color;
this.speed = speed ;
this.move_length = move_length;
this.eps = 0.01;
this.damage = damage;
}
start(){
}
update(){
if(this.move_length < this.eps){
this.destroy();
return false;
}
this.update_move();
if(this.player.charactr !== "enemy"){
this.update_attack();
}
this.render();
}
update_move(){
let moved = Math.min(this.move_length,this.speed * this.timedelta / 1000);
this.x += this.vx * moved;
this.y += this.vy * moved;
this.move_length -= moved;
}
update_attack(){
for ( let i=0;i<this.playground.players.length; i++ ){
let player = this.playground.players[i];
if(this.player !== player && this.is_collision(player)){
this.attack(player);
}
}
}
get_dist(x1,y1,x2,y2){
let dx= x1-x2;
let dy = y1-y2;
return Math.sqrt(dx*dx + dy*dy);
}
is_collision(obj){
let distance = this.get_dist(this.x,this.y,obj.x,obj.y);
if(distance < this.radius + obj.radius)
return true;
return false;
}
attack(player){
let angle = Math.atan2(player.y - this.y,player.x-this.x);
player.is_attacked(angle,this.damage);
if (this.playground.mode === "multi mode"){
console.log(this.damage);
this.playground.mps.send_attack(player.uuid,player.x,player.y,angle,this.damage,this.uuid);
}
this.destroy();
}
render(){
let scale = this.playground.scale
this.ctx.beginPath();
this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0,
Math.PI * 2, false); this.ctx.fillStyle = this.color;
this.ctx.fill(); }
on_destroy() {
let fireballs = this.player.fireballs;
for(let i=0;i<fireballs.length;i++)
if(fireballs[i] === this){
fireballs.splice(i,1);
break;
}
}
}
class MultiPlayerSocket {
constructor(playground) {
this.playground = playground;
this.ws = new WebSocket("wss://app6641.acapp.acwing.com.cn/wss/multiplayer/?token=" + playground.root.access);
this.start();
}
start() {
this.receive();
}
receive () {
let outer = this;
this.ws.onmessage = function(e) {
let data = JSON.parse(e.data);
let uuid = data.uuid;
if (uuid === outer.uuid) return false;
let event = data.event;
if (event === "create_player") {
outer.receive_create_player(uuid, data.username, data.photo);
} else if (event === "move_to") {
outer.receive_move_to(uuid, data.tx, data.ty);
} else if (event === "shoot_fireball") {
outer.receive_shoot_fireball(uuid, data.tx, data.ty, data.ball_uuid);
} else if (event === "attack") {
outer.receive_attack(uuid, data.attackee_uuid, data.x, data.y, data.angle, data.damage, data.ball_uuid);
} else if (event === "blink") {
outer.receive_blink(uuid, data.tx, data.ty);
} else if(event === "message"){
outer.receive_message(uuid,data.text);
}
};
}
send_create_player(username, photo) {
let outer = this;
this.ws.send(JSON.stringify({
'event': "create_player",
'uuid': outer.uuid,
'username': username,
'photo': photo,
}));
}
get_player(uuid) {
let players = this.playground.players;
for (let i = 0; i < players.length; i ++ ) {
let player = players[i];
if (player.uuid === uuid)
return player;
}
return null;
}
receive_create_player(uuid, username, photo) {
let player = new Player(
this.playground,
this.playground.width / 2 / this.playground.scale,
0.5,
0.05,
"white",
0.15,
"enemy",
username,
photo,
);
player.uuid = uuid;
this.playground.players.push(player);
}
send_move_to(tx, ty) {
let outer = this;
this.ws.send(JSON.stringify({
'event': "move_to",
'uuid': outer.uuid,
'tx': tx,
'ty': ty,
}));
}
receive_move_to(uuid, tx, ty) {
let player = this.get_player(uuid);
if (player) {
player.move_to(tx, ty);
}
}
send_shoot_fireball(tx, ty, ball_uuid) {
let outer = this;
this.ws.send(JSON.stringify({
'event': "shoot_fireball",
'uuid': outer.uuid,
'tx': tx,
'ty': ty,
'ball_uuid': ball_uuid,
}));
}
receive_shoot_fireball(uuid, tx, ty, ball_uuid) {
let player = this.get_player(uuid);
if (player) {
let fireball = player.shoot_fireball(tx, ty);
fireball.uuid = ball_uuid;
}
}
send_attack(attackee_uuid, x, y, angle, damage, ball_uuid) {
let outer = this;
this.ws.send(JSON.stringify({
'event': "attack",
'uuid': outer.uuid,
'attackee_uuid': attackee_uuid,
'x': x,
'y': y,
'angle': angle,
'damage': damage,
'ball_uuid': ball_uuid,
}));
}
receive_attack(uuid, attackee_uuid, x, y, angle, damage, ball_uuid) {
let attacker = this.get_player(uuid);
let attackee = this.get_player(attackee_uuid);
if (attacker && attackee) {
attackee.receive_attack(x, y, angle, damage, ball_uuid, attacker);
}
}
send_blink(tx, ty) {
let outer = this;
this.ws.send(JSON.stringify({
'event': "blink",
'uuid': outer.uuid,
'tx': tx,
'ty': ty,
}));
}
receive_blink(uuid, tx, ty) {
let player = this.get_player(uuid);
if (player) {
player.blink(tx, ty);
}
}
send_message(text){
let outer = this;
this.ws.send(JSON.stringify({
'event':"message",
'uuid':outer.uuid,
'text':text,
}));
}
receive_message(uuid,text){
let player = this.get_player(uuid);
if(player){
player.playground.chat_field.add_message(player.username,text);
}
}
}
class AcGamePlayground {
constructor(root){
this.root=root;
this.$playground = $(`<div class="ac-game-playground"></div>`);
this.hide();
this.root.$ac_game.append(this.$playground);
this.start();
}
get_random_color(){
let colors = ["blue","red","green","pink","grey"];
return colors[Math.floor(Math.random()*5)];
}
start(){
let outer=this;
let uuid = this.create_uuid();
$(window).on(`resize.${uuid}`,function(){
outer.resize();
});
if(this.root.AcWingOS){
this.root.AcWingOS.api.window.on_close(function(){
$(window).off(`resize.${uuid}`);
});
}
}
create_uuid() {
let res = "";
for(let i = 0;i < 8 ; i++){
let x = parseInt(Math.floor(Math.random()*10));
res += x;
}
return res;
}
resize(){
this.width = this.$playground.width();
this.height = this.$playground.height();
this.unit= Math.min(this.width/16,this.height/9);
this.width = this.unit * 16;
this.height = this.unit*9;
this.scale = this.height;
if(this.game_map)this.game_map.resize();
}
update(){
}
show(mode){
let outer = this;
this.$playground.show();
this.$playground.resize();
this.width= this.$playground.width();
this.height = this.$playground.height();
this.game_map = new GameMap(this);
this.resize();
this.players = [];
this.players.push(new Player(this,this.width/2/this.scale,0.5,0.05,"white",0.15,"me",this.root.settings.username,this.root.settings.photo));
this.mode = mode;
this.state = "waiting";
this.notice_board = new NoticeBoard(this);
this.score_board = new ScoreBoard(this);
this.player_count = 0;
if(mode === "single mode")
for (let i = 0; i < 5; i ++ ) {
this.players.push(new Player(this, this.width / 2/this.scale, 0.5, 0.05, this.get_random_color(), 0.15, "robot"));
} else if(mode === "multi mode"){
this.chat_field = new ChatField(this);
this.mps = new MultiPlayerSocket(this);
this.mps.uuid = this.players[0].uuid;
this.mps.ws.onopen = function(){
outer.mps.send_create_player(outer.root.settings.username,outer.root.settings.photo);
};
}
}
hide(){
while(this.players && this.players.length > 0){
this.players[0].destroy();
}
if(this.game_map){
this.game_map.destroy();
this.game_map = null;
}
if(this.notice_board){
this.notice_board.destroy();
this.notice_board = null;
}
if(this.score_board){
this.score_board.destroy();
this.score_board = null;
}
this.$playground.empty();
this.$playground.hide();
}
}
class Settings{
constructor(root){
this.root = root;
this.platform = "WEB";
if(this.root.AcWingOS) this.platform = "ACAPP";
this.username = "";
this.photo = "https://cdn.acwing.com/media/user/profile/photo/355448_sm_2015d90652.jpg";
this.$settings = $(`
<div class="ac-game-settings">
<div class="ac-game-settings-login">
<div class="ac-game-settings-title">
登录
</div>
<div class="ac-game-settings-username">
<div class="ac-game-settings-item">
<input type="text" placeholder="用户名">
</div>
</div>
<div class="ac-game-settings-password">
<div class="ac-game-settings-item">
<input type="password" placeholder="密码">
</div>
</div>
<div class="ac-game-settings-submit">
<div class="ac-game-settings-item">
<button>登录</button>
</div>
</div>
<div class="ac-game-settings-error-message">
</div>
<br>
<br>
<div class="ac-game-settings-option">
注册
</div>
<br>
<div class="ac-game-settings-acwing">
<img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
<br>
<br>
<div>
AcWing一键登录
</div>
</div>
</div>
<div class="ac-game-settings-register">
<div class="ac-game-settings-title">
注册
</div>
<div class="ac-game-settings-username">
<div class="ac-game-settings-item">
<input type="text" placeholder="用户名">
</div>
</div>
<div class="ac-game-settings-password ac-game-settings-password-first">
<div class="ac-game-settings-item">
<input type="password" placeholder="密码">
</div>
</div>
<div class="ac-game-settings-password ac-game-settings-password-second">
<div class="ac-game-settings-item">
<input type="password" placeholder="确认密码">
</div>
</div>
<div class="ac-game-settings-submit">
<div class="ac-game-settings-item">
<button>注册</button>
</div>
</div>
<div class="ac-game-settings-error-message">
</div>
<br>
<br>
<div class="ac-game-settings-option">
登录
</div>
<div class="ac-game-settings-acwing">
<img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
<br>
<br>
<div>
AcWing一键登录
</div>
</div>
</div>
<div>
</div>
</div>
`);
this.$login = this.$settings.find(".ac-game-settings-login");
this.$login_username = this.$login.find(".ac-game-settings-username input");
this.$login_password = this.$login.find(".ac-game-settings-password input");
this.$login_submit = this.$login.find(".ac-game-settings-submit button");
this.$login_error_message = this.$login.find(".ac-game-settings-error-message");
this.$login_register = this.$login.find(".ac-game-settings-option");
this.$login.hide();
this.$register = this.$settings.find(".ac-game-settings-register");
this.$register_username = this.$register.find(".ac-game-settings-username input");
this.$register_password = this.$register.find(".ac-game-settings-password-first input");
this.$register_password_confirm = this.$register.find(".ac-game-settings-password-second input");
this.$register_submit = this.$register.find(".ac-game-settings-submit button");
this.$register_error_message = this.$register.find(".ac-game-settings-error-message");
this.$register_login = this.$register.find(".ac-game-settings-option");
this.$register.hide();
this.$acwing_login = this.$settings.find(".ac-game-settings-acwing img");
this.root.$ac_game.append(this.$settings);
this.start();
}
start(){
if (this.platform === "ACAPP"){
this.getinfo_acapp();
}else{
if(this.root.access){
this.getinfo_web();
this.refresh_jwt_token();
} else {
this.login();
}
this.add_listening_events();
}
}
refresh_jwt_token(){
setInterval(() => {
$.ajax({
url:"https://app6641.acapp.acwing.com.cn/settings/token/refresh/",
type:"post",
data:{
refresh:this.root.refresh,
},
success: resp => {
this.root.access = resp.access;
}
});
},4.5*60*1000);
setTimeout(() => {
$.ajax({
url:"https://app6641.acapp.acwing.com.cn/settings/ranklist/",
type:"GET",
headers:{
'Authorization': "Bearer "+ this.root.access,
},
success: resp => {
console.log(resp);
}
});
},5000);
}
add_listening_events(){
let outer = this;
this.add_listening_events_login();
this.add_listening_events_register();
this.$acwing_login.click(function(){
outer.acwing_login();
});
}
add_listening_events_login(){
let outer =this;
this.$login_register.click(function(){
outer.register();
});
this.$login_submit.click(function(){
outer.login_on_remote();
});
}
add_listening_events_register(){
let outer = this;
this.$register_login.click(function(){
outer.login();
});
this.$register_submit.click(function() {
outer.register_on_remote();
});
}
acwing_login() {
$.ajax({
url: "https://app6641.acapp.acwing.com.cn/settings/acwing/web/apply_code/",
type: "GET",
success: function(resp) {
if (resp.result === "success") {
window.location.replace(resp.apply_code_url);
}
}
});
}
login_on_remote(username , password) {
let outer = this;
username = username || this.$login_username.val();
password = password || this.$login_password.val();
this.$login_error_message.empty();
$.ajax({
url: "https://app6641.acapp.acwing.com.cn/settings/token/",
type: "post",
data: {
username: username,
password: password,
},
success: resp =>{
this.root.access = resp.access;
this.root.refresh = resp.refresh;
this.refresh_jwt_token();
this.getinfo_web();
},
error:() => {
this.$login_error_message.html("用户名密码错误");
},
});
}
register_on_remote(){
let outer = this;
let username = this.$register_username.val();
let password = this.$register_password.val();
let password_confirm = this.$register_password_confirm.val();
this.$register_error_message.empty();
$.ajax({
url: "https://app6641.acapp.acwing.com.cn/settings/register/",
type: "POST",
data: {
username: username,
password: password,
password_confirm:password_confirm,
},
success: resp =>{
if(resp.result === "success"){
this.login_on_remote(username,password);
} else {
this.$register_error_message.html(resp.result);
}
}
});
}
logout_on_remote(){
if(this.platform === "ACAPP") {
this.root.AcWingOS.api.window.close();
} else {
this.root.access = "";
this.root.refresh = "";
location.href = "/";
}
}
login(){//打开登陆界面
this.$register.hide();
this.$login.show();
}
register(){// 打开注册界面
this.$login.hide();
this.$register.show();
}
acapp_login(appid, redirect_uri, scope, state) {
let outer = this;
this.root.AcWingOS.api.oauth2.authorize(appid, redirect_uri, scope, state, function(resp) {
if (resp.result === "success") {
outer.username = resp.username;
outer.photo = resp.photo;
outer.hide();
outer.root.menu.show();
outer.root.access = resp.access;
outer.root.refresh = resp.refresh;
outer.refresh_jwt_token();
}
});
}
getinfo_acapp(){
let outer = this;
$.ajax({
url: "https://app6641.acapp.acwing.com.cn/settings/acwing/acapp/receive_code/",
type:"GET",
success: function(resp){
if(resp.result === "success"){
outer.acapp_login(resp.appid,resp.redirect_uri,resp.scope,resp.state);
}
}
});
}
getinfo_acapp() {
let outer = this;
$.ajax({
url: "https://app6641.acapp.acwing.com.cn/settings/acwing/acapp/apply_code/",
type: "GET",
success: function(resp) {
if (resp.result === "success") {
outer.acapp_login(resp.appid, resp.redirect_uri, resp.scope, resp.state);
}
}
});
}
getinfo_web(){
let outer = this;
$.ajax({
url:"https://app6641.acapp.acwing.com.cn/settings/getinfo/",
type:"get",
data:{
platform:outer.platform,
},
headers:{
'authorization':"Bearer "+this.root.access,
},
success:function(resp){
console.log(resp);
if(resp.result === "success"){
outer.username = resp.username;
outer.photo = resp.photo;
outer.hide();
outer.root.menu.show();
} else {
outer.login();
}
},
});
}
hide(){
this.$settings.hide();
}
show(){
this.$settings.show();
}
}
export class AcGame {
constructor(id, AcWingOS, access, refresh) {
this.id = id;
this.$ac_game = $('#' + id);
this.AcWingOS = AcWingOS;
this.access = access;
this.refresh = refresh;
this.settings = new Settings(this);
this.menu = new AcGameMenu(this);
this.playground = new AcGamePlayground(this);
this.start();
}
start() {
}
}