HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{margin:0;padding:0}
button,input{padding:20px;outline:none;}
.map{
width:800px;
height:600px;
background: url(‘./imgs/bg.png‘) repeat;
border:10px solid purple;
margin:100px auto;
position:relative;
}
.map>.food{
width:20px;
height:20px;
background-image:url(‘./imgs/food.png‘);
position:absolute;
left:100px;
top:100px;
}
.map>.head{
width:20px;
height:20px;
background-image:url(‘./imgs/head.png‘);
position:absolute;
left:0;
top:0;
}
.map>.body{
width:20px;
height:20px;
background-image:url(‘./imgs/body.png‘);
position:absolute;
left:80px;
top:0;
}
.popup{
position:fixed;
border:2px double yellow;
/* height:80px; */
/* width:200px; */
margin: 20px auto -60px;
padding:0 20px;
background-color: rgb(84,84,84);
color:#fff;
text-align:center;
line-height:80px;
border-radius:20px;
left:50%;
top:50px;
font-size:20px;
transform:translateX(-50%);
display:none;
}
.popup::after{
content:‘\1F609‘;
position:absolute;
left:100%;
}
</style>
</head>
<body>
<button class="start">start</button>
<button class="stop">stop</button>
<button class="restart">restart</button>
<input type="text" value=‘0‘ class=‘score‘ disabled>
<div class="popup">popup</div>
<div class="map">
<!-- <div class="food"></div>
<div class="head"></div>
<div class="body"></div>
<div class="body"></div> -->
</div>
<script src="./main.js" type=‘module‘></script>
<script>
// const map=document.querySelector(‘.map‘)
// const f=new Food(map)
// console.log(f)
// const snake=new Snake(map)
// console.log(snake)
</script>
</body>
</html>
greedysnake.js
import Food from ‘./food.js‘
import Snake from ‘./snake.js‘
export default class GreedySnake{
constructor(elem,score,popup){
this.map=document.querySelector(elem)
this.timer=null
this.level=1
this.food=new Food(this.map)
this.snake=new Snake(this.map)
this.score=document.querySelector(score)
this.count=0
this.steer()
this.popup=document.querySelector(popup)
this.flag=true
}
start(){
this.timer=setInterval(()=>{
this.alert()
this.snake.motion()
let flag=this.snake.achieve(this.food)
// console.log(‘this.food‘,this.food,this.food.food.offsetLeft,this.food.food.offsetTop)
if(flag){
this.updateScore()
this.snake.defineHead()
this.food.generator()
}
if(this.snake.termination()){
clearInterval(this.timer)
// window.alert(‘Game Over!!!‘)
if(window.confirm(‘Oops! Game Over! Do you want to restart ?‘)){
this.restart()
}
}
},400-this.level*50)
}
stop(){
window.clearInterval(this.timer)
}
restart(){
window.location.reload()
}
steer(){
document.addEventListener(‘keydown‘,e=>{
e.preventDefault()
// console.log(e.key)
switch(e.key){
case ‘ArrowUp‘: this.snake.bearing=‘top‘;break
case ‘ArrowDown‘: this.snake.bearing=‘bottom‘;break
case ‘ArrowLeft‘: this.snake.bearing=‘left‘;break
case ‘ArrowRight‘: this.snake.bearing=‘right‘;break
}
})
}
alert(){
if(this.count%1===0 && this.flag){
if(this.count !== 0){
this.popup.innerHTML=`^_^ Congratulations, promote to level: ${this.level}`
}else{
this.popup.innerHTML=`^_^ level: ${this.level}`
}
this.popup.style.display=‘block‘;
this.flag=false
setTimeout(()=>{
this.popup.style.display=‘none‘
},1500)
}
}
updateScore(){
this.count++
// console.log(‘count: ‘,this.count,typeof this.score.value,this.score.value)
this.score.value=parseInt(this.score.value)+this.level*10
if(this.count%1===0){
this.flag=true
this.level++
this.stop()
this.start()
}
}
}
snake.js
export default class Snake{
constructor(map){
this.map=map
this.snake=[]
this.bearing=‘right‘
this.initialize()
}
getBearing(){
const head=this.snake[0]
if(!head) return {left:0,right:0}
const bearing={left:head.offsetLeft,top:head.offsetTop}
switch(this.bearing){
case ‘top‘: bearing.top-=20;break
case ‘right‘: bearing.left+=20;break
case ‘bottom‘: bearing.top+=20;break
case ‘left‘: bearing.left-=20;break
}
// console.log(‘getBearing‘,bearing)
return bearing
}
defineHead(){
const position=this.getBearing()
// console.log(‘defineHead‘,position)
const head=this.snake[0]
if(head) head.className=‘body‘
const div=document.createElement(‘div‘)
div.className=‘head‘
div.style.left=position.left+‘px‘
div.style.top=position.top+‘px‘
this.snake.unshift(div)
this.map.appendChild(div)
}
initialize(){
const num=3;
for(let i=0;i<num;++i){
this.defineHead()
}
}
motion(){
const body=this.snake.pop()
body.remove()
this.defineHead()
}
termination(){
const head=this.snake[0]
const x=head.offsetLeft
const y=head.offsetTop
if(x<0 || y<0 || x>this.map.clientWidth || y>this.map.clientHeight){
return true
}else{
let flag=false
const body=this.snake.slice(1)
body.forEach((value,index,array)=>{
if(value.offsetLeft === x && value.offsetTop === y) flag=true
})
return flag
}
}
achieve(food){
const x=this.snake[0].offsetLeft
const y=this.snake[0].offsetTop
if(x === food.food.offsetLeft && y === food.food.offsetTop) return true
return false
}
}
food.js
export default class Food{
constructor(map){
this.map=map
this.food=document.createElement(‘div‘)
this.food.className=‘food‘
this.map.appendChild(this.food)
this.x=0
this.y=0
this.generator()
}
generator(){
const numberX=this.map.clientWidth/this.food.clientWidth
const numberY=this.map.clientHeight/this.food.clientHeight
const x=Math.floor(Math.random()*numberX)
const y=Math.floor(Math.random()*numberY)
this.food.style.left=x*20+‘px‘
this.food.style.top=y*20+‘px‘
// console.log(‘food‘,x,y,this.food.offsetLeft,this.food.offsetTop)
}
}
main.js
import GreedySnake from ‘./greedysnake.js‘
const pastime=new GreedySnake(‘.map‘,‘.score‘,‘.popup‘)
const startButton=document.querySelector(‘.start‘)
startButton.addEventListener(‘click‘,()=>pastime.start())
const stopButton=document.querySelector(‘.stop‘)
stopButton.addEventListener(‘click‘,()=>pastime.stop())
const restartButton=document.querySelector(‘.restart‘)
restartButton.addEventListener(‘click‘,()=>pastime.restart())
body.png
head.png
bg.png
food.png