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.
453 lines
12 KiB
453 lines
12 KiB
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-single-mode">
|
|
单人模式
|
|
</div>
|
|
<br>
|
|
<div class="ac-game-menu-field-item ac-game-menu-field-item-multi-mode">
|
|
多人模式
|
|
</div>
|
|
<br>
|
|
<div class="ac-game-menu-field-item ac-game-menu-field-item-settings">
|
|
设置
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`);
|
|
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.start();
|
|
}
|
|
|
|
start(){
|
|
this.add_listening_events();
|
|
}
|
|
|
|
add_listening_events(){
|
|
|
|
let outer = this;
|
|
this.$single_mode.click(function(){
|
|
outer.hide();
|
|
outer.root.playground.show();
|
|
|
|
});
|
|
this.$multi_mode.click(function(){
|
|
console.log("aaac");
|
|
});
|
|
this.$settings.click(function(){
|
|
console.log("aaa");
|
|
});
|
|
}
|
|
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; // 当前帧距离上一帧的时间间隔
|
|
}
|
|
|
|
start() { // 只会在第一帧执行一次
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
last_timestamp = timestamp;
|
|
|
|
requestAnimationFrame(AC_GAME_ANIMATION);
|
|
}
|
|
|
|
|
|
requestAnimationFrame(AC_GAME_ANIMATION);
|
|
|
|
class GameMap extends AcGameObject{
|
|
constructor(playground){
|
|
super();
|
|
this.playground=playground;
|
|
this.$canvas = $(`<canvas></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(){
|
|
|
|
}
|
|
|
|
|
|
update(){
|
|
this.render();
|
|
}
|
|
|
|
render(){
|
|
this.ctx.fillStyle = "rgba(0,0,0,0.1)";
|
|
this.ctx.fillRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
|
|
}
|
|
}
|
|
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 = 1;
|
|
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(){
|
|
this.ctx.beginPath();
|
|
this.ctx.arc(this.x,this.y,this.radius,0,Math.PI * 2,false);
|
|
this.ctx.fillStyle = this.color;
|
|
this.ctx.fill();
|
|
}
|
|
}
|
|
class Player extends AcGameObject {
|
|
constructor(playground,x,y,radius,color,speed,is_me){
|
|
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.is_me=is_me;
|
|
this.eps= 0.01;
|
|
this.cur_skill = null;
|
|
this.fraction = 0.9;
|
|
this.spent_time = 0;
|
|
|
|
}
|
|
|
|
add_listening_events() {
|
|
let outer = this;
|
|
this.playground.game_map.$canvas.on("contextmenu",function(){
|
|
return false;
|
|
});
|
|
this.playground.game_map.$canvas.mousedown(function(e){
|
|
const rect = outer.ctx.canvas.getBoundingClientRect();
|
|
|
|
if(e.which === 3){
|
|
outer.move_to(e.clientX - rect.left,e.clientY - rect.top);
|
|
} else if (e.which === 1){
|
|
if ( outer.cur_skill === "fireball" ){
|
|
outer.shoot_fireball(e.clientX - rect.left,e.clientY - rect.top);
|
|
}
|
|
outer.cur_skill = null;
|
|
}
|
|
});
|
|
$(window).keydown(function(e){
|
|
if(e.which === 81){
|
|
outer.cur_skill = "fireball";
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
shoot_fireball(tx,ty){
|
|
let x =this.x,y=this.y;
|
|
let radius = this.playground.height * 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 = this.playground.height * 1.5;
|
|
let move_length = this.playground.height * 1;
|
|
new FireBall(this.playground,this,x,y,radius,vx,vy,"orange",speed,move_length,this.playground.height*0.01);
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
start(){
|
|
if(this.is_me){
|
|
this.add_listening_events();
|
|
} else{
|
|
let tx= Math.random() *this.playground.width;
|
|
let ty = Math.random() *this.playground.height;
|
|
this.move_to(tx,ty);
|
|
}
|
|
}
|
|
|
|
is_attacked(angle,damage){
|
|
for(let i = 0;i<10+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 * 7;
|
|
let move_length = this.radius *Math.random()*10;
|
|
new Particle(this.playground,x,y,radius,vx,vy,color,speed,move_length);
|
|
|
|
}
|
|
|
|
this.radius -= damage;
|
|
if(this.radius<5){
|
|
this.destroy();
|
|
return false;
|
|
}
|
|
this.damage_x = Math.cos(angle);
|
|
this.damage_y = Math.sin(angle);
|
|
this.damage_speed = damage *100;
|
|
this.speed *= 0.9;
|
|
|
|
}
|
|
|
|
|
|
update(){
|
|
this.spent_time += this.timedelta/1000;
|
|
if(!this.is_me && this.spent_time > 5 &&Math.random() < 1/180.0){
|
|
let player = this.playground.players[Math.floor(Math.random()* this.playground.players.length)];
|
|
|
|
this.shoot_fireball(player.x,player.y);
|
|
}
|
|
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.fraction;
|
|
|
|
}else{
|
|
|
|
if(this.move_length<this.eps){
|
|
this.move_length=0;
|
|
this.vx=this.vy=0;
|
|
if(!this.is_me){
|
|
let tx= Math.random() *this.playground.width;
|
|
let ty = Math.random() *this.playground.height;
|
|
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;
|
|
}
|
|
}
|
|
this.render();
|
|
}
|
|
render(){
|
|
this.ctx.beginPath();
|
|
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
|
|
this.ctx.fillStyle = this.color;
|
|
this.ctx.fill();
|
|
|
|
}
|
|
on_destroy(){
|
|
for(let i=0;i<this.playground.players.length;i++){
|
|
if(this.playground.players[i] === this){
|
|
this.playground.players.splice(i,1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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 = 1;
|
|
this.damage = damage;
|
|
|
|
}
|
|
start(){
|
|
}
|
|
|
|
update(){
|
|
if(this.move_length < 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.move_length -= moved;
|
|
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);
|
|
}
|
|
}
|
|
this.render();
|
|
}
|
|
|
|
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);
|
|
this.destroy();
|
|
}
|
|
|
|
render(){
|
|
this.ctx.beginPath();
|
|
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
|
|
this.ctx.fillStyle = this.color;
|
|
this.ctx.fill();
|
|
}
|
|
}
|
|
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.width= this.$playground.width();
|
|
this.height = this.$playground.height();
|
|
this.game_map = new GameMap(this);
|
|
this.players = [];
|
|
this.players.push(new Player(this,this.width/2,this.height/2,this.height*0.05,"white",this.height*0.15,true));
|
|
for (let i = 0; i < 5; i ++ ) {
|
|
this.players.push(new Player(this, this.width / 2, this.height / 2, this.height * 0.05, this.get_random_color(), this.height * 0.15, false));
|
|
}
|
|
|
|
this.start();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
get_random_color(){
|
|
let colors = ["blue","red","green","pink","grey"];
|
|
return colors[Math.floor(Math.random()*5)];
|
|
}
|
|
|
|
start(){
|
|
|
|
}
|
|
|
|
update(){
|
|
|
|
}
|
|
|
|
show(){
|
|
this.$playground.show();
|
|
}
|
|
|
|
hide(){
|
|
this.$playground.hide();
|
|
}
|
|
}
|
|
export class AcGame {
|
|
constructor(id){
|
|
this.id = id;
|
|
this.$ac_game = $('#'+id);
|
|
//this.menu = new AcGameMenu(this);
|
|
this.playground = new AcGamePlayground(this);
|
|
this.start();
|
|
}
|
|
start() {
|
|
}
|
|
}
|