水果贪吃蛇
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.
 
 
 

290 lines
9.9 KiB

import { AcGameObject } from './AcGameObject';
import { Cell } from './Cell';
export class Snake extends AcGameObject {
constructor(ctx, gamemap) {
super();
this.ctx = ctx;
this.gamemap = gamemap;
this.cells = [];
this.color = "#4876ec";
this.dirs = [
{x: 0, y: -1},
{x: 1, y: 0},
{x: 0, y: 1},
{x: -1, y: 0},
];
this.direction = 2;
this.eps = 1e-1;
this.speed = 5; // 每秒钟走几格
this.apple_cell = new Cell(-1, -1);
this.apple_img = new Image();
this.apple_img.src = "https://test.bnblogs.cc/acapp/images/apple/apple_00.png";
this.eating = false;
this.tail_cell = null;
this.number = 0;
this.head = null;
this.eye_direction = 1 // 初始的蛇眼睛朝右(0:上 1:右 2:下 3:左)
// 定义蛇左右眼的x和y坐标的偏移量
this.eyes_dx = [
[-1,1],
[1,1],
[-1,1],
[-1,-1]
];
this.eyes_dy = [
[-1,-1],
[-1,1],
[1,1],
[-1,1]
];
this.index = 0; // 当前的水果是哪个,来判断吃完之后的颜色
this.grades = 1; // 水果分值
}
start() {
this.cells.push(new Cell(4, 7));
for (let i = 4; i >= 1; i -- ) {
this.cells.push(new Cell(i, 7));
}
this.put_an_apple();
}
put_an_apple() {
const positions = new Set();
for (let i = 0; i < 17; i ++ ) {
for (let j = 0; j < 15; j ++ ) {
positions.add(`${i}-${j}`);
}
}
for (let cell of this.cells) {
positions.delete(`${cell.i}-${cell.j}`);
}
const items = Array.from(positions);
if (items.length === 0) this.gamemap.win();
else {
let [x, y] = items[Math.floor(Math.random() * items.length)].split('-');
x = parseInt(x), y = parseInt(y);
this.apple_cell = new Cell(x, y);
}
}
get_direction(a, b) {
if (Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps)
return -1;
if (Math.abs(a.x - b.x) < this.eps) {
if (b.y < a.y) return 0;
return 2;
}
if (b.x > a.x) return 1;
return 3;
}
check_die() {
const head = this.cells[0];
if (head.i < 0 || head.i >= 17 || head.j < 0 || head.j >= 15)
return true;
for (let i = 2; i < this.cells.length; i ++ ) {
if (head.i === this.cells[i].i && head.j === this.cells[i].j) {
return true;
}
}
return false;
}
update_body() {
const k = this.cells.length - 1;
const d = this.get_direction(this.cells[k], this.cells[k - 1]);
if (d >= 0) {
const distance = this.speed * this.timedelta / 1000;
this.cells[k].x += this.dirs[d].x * distance;
this.cells[k].y += this.dirs[d].y * distance;
this.cells[0].x += this.dirs[this.direction].x * distance;
this.cells[0].y += this.dirs[this.direction].y * distance;
} else {
const new_cells = [];
const headi = this.cells[1].i + this.dirs[this.direction].x;
const headj = this.cells[1].j + this.dirs[this.direction].y;
new_cells.push(new Cell(headi, headj));
new_cells.push(new Cell(headi, headj));
this.head = new Cell(headi,headj);
for (let i = 1; i < k; i ++ ) {
new_cells.push(this.cells[i]);
}
this.cells = new_cells;
if (this.eating) {
this.cells.push(this.tail_cell);
this.eating = false;
this.tail_cell = null;
}
const ds = this.gamemap.directions;
while (ds.length > 0 && (ds[0] === this.direction || ds[0] === (this.direction ^ 2)))
ds.splice(0, 1);
if (ds.length > 0) {
this.direction = ds[0];
ds.splice(0, 1);
}
if (this.check_die()) {
this.gamemap.lose();
}
if (headi === this.apple_cell.i && headj === this.apple_cell.j) {
if (this.gamemap.store.state.music === true) {
const audio = document.querySelector('#eat_apple');
audio.play();
audio.currentTime=0.4
audio.playbackRate = 3
}
this.eating = true;
if (this.index === 5) {
this.color = "#efefef";
this.grades = 5;
}
else if (this.index === 1) {
this.color = "#ffd201";
this.grades = 5;
}
else if (this.index === 17)
{
this.color = "#ff9999";
this.grades = 5;
}
else if (this.index === 7 || this.index === 0 || this.index === 8 || this.index === 12 || this.index === 20 || this.index === 19){
this.color= "#f2383b";
this.grades = 1;
}
else if (this.index === 11 || this.index === 13 || this.index === 14 || this.index === 15){
this.color= "#34b43d";
this.grades = 3;
}
else if (this.index === 3 || this.index === 6 || this.index === 10){
this.color = "#b445f1";
this.grades = 4;
}
else {
this.color = "#ea881c";
this.grades = 2;
}
const cell = this.cells[this.cells.length - 1];
this.tail_cell = new Cell(cell.i, cell.j);
this.put_an_apple();
// 换不同apple图片
const index_number = Math.round(this.randomNum(0,20));
this.index = index_number;
let src_head = "https://test.bnblogs.cc/acapp/images/apple/apple_0";
const src_tail = ".png";
if (index_number >= 0 && index_number <=9) {
this.apple_img.src = src_head + index_number + src_tail;
}else {
src_head = src_head.substring(0,src_head.length - 1);
this.apple_img.src = src_head + index_number + src_tail;
}
console.log(this.grades);
// console.log(this.apple_img.src,typeof this.apple_img.src);
const score = this.gamemap.store.state.score + this.grades;
this.gamemap.store.commit('updateScore', score);
this.gamemap.store.commit('updateRecord', Math.max(score,this.gamemap.store.state.record));
this.number++;
this.gamemap.store.commit('updateNumber',this.number);
if (this.number > 0 && this.number % 20 === 0) {
// 吃20个进入下一回合,依次奖励10-20-30
this.speed = this.speed + 1;
this.gamemap.store.commit("updateSpeed",this.speed);
this.gamemap.store.commit("updateScore",score + 10 * (parseInt(this.number / 20)));
this.gamemap.store.commit('updateRecord', Math.max(this.gamemap.store.state.score,this.gamemap.store.state.record));
this.gamemap.store.commit('updateColor',this.color);
this.gamemap.snake.destroy();
this.gamemap.store.commit('updateNextStep',true);
this.gamemap.status='waiting';
}
// console.log("num: ",this.number);
// console.log("speed: ",this.speed);
}
}
}
update() {
if (this.gamemap.status === "playing") {
this.update_body();
}
this.render();
}
randomNum (n,m) {
var result = Math.random()*(m+1-n)+n;
while(result>m) {
result = Math.random()*(m+1-n)+n;
}
return result;
}
render() {
const L = this.gamemap.L;
if (this.eating) {
this.cells.push(this.tail_cell);
}
this.ctx.drawImage(this.apple_img, this.apple_cell.i * L, this.apple_cell.j * L, L, L);
this.ctx.fillStyle = this.color;
for (let cell of this.cells) {
this.ctx.beginPath();
this.ctx.arc(cell.x * L, cell.y * L, L / 2 * 0.8, 0, Math.PI * 2);
this.ctx.fill();
}
for (let i = 1; i < this.cells.length; i ++ ) {
const a = this.cells[i - 1], b = this.cells[i];
if (Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps) {
continue;
}
if (Math.abs(a.x - b.x) < this.eps) {
this.ctx.fillRect((a.x - 0.5 + 0.1) * L, Math.min(a.y, b.y) * L, L * 0.8, Math.abs(a.y - b.y) * L);
} else {
this.ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - 0.5 + 0.1) * L, Math.abs(a.x - b.x) * L, L * 0.8);
}
}
if (this.eye_direction !== -1) {
// 画出蛇的眼睛
this.ctx.fillStyle = "black";
for (let i = 0; i < 2 ; i++) {
const eye_x = (this.cells[0].x + this.eyes_dx[this.eye_direction][i] * 0.2) * L;
const eye_y = (this.cells[0].y + this.eyes_dy[this.eye_direction][i] * 0.2) * L;
// 画眼睛
this.ctx.beginPath();
this.ctx.arc(eye_x,eye_y,L*0.05,0,Math.PI*2);
this.ctx.fill();
}
}
if (this.eating) {
this.cells.pop();
}
}
}