<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>RetroPython</title> <!-- // <script src="http://apps.bdimg.com/libs/jquery/2.0.0/jquery.min.js"></script> // <script type="text/javascript" src="http://cdn.bootcss.com/socket.io/1.4.8/socket.io.min.js"></script> --> <!-- // <script src="js/jquery.min.js"></script> --> <script src="./static/socket.io.min.js"></script> <script src="./static/jquery.min.js"></script> <style> </style> <script> var isPi = 0 var prot = 80 function deepCopy(p, c) { var c = c || {}; for (var i in p) { if (typeof p[i] === 'object') { c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]); } else { c[i] = p[i]; } } return c; } int = parseInt float = parseFloat log = console.log debug = console.debug info = console.info table = console.table len=(x)=>x.length rn = (x)=> int(x*Math.random()) function range (f,n,max) { // 1.Python 用法 // 2.执行 f(n['property']) 并返回新的 [] 或 {} // range(10) =>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // range(x=>x*2,5,10) =>[10, 12, 14, 16, 18] // range(x=>x+x,['a', 'b', 'c']) // =>["aa", "bb", "cc"] var flag = (typeof f == "number") if(flag){ max =(typeof n == "number")?n:max n = f f = x=>x } var items = n var obj = (n.constructor === Array)?[]:{} if(typeof n == "number"){ obj = [] items = [] var i=max?n:0 max=max||n while(i!=max){items.push(i);i++} } for (var i in items) { obj[i]=f(items[i]) } return obj } sum = (arr)=>{ var summ = 0 for (var i in arr){ summ += arr[i] } return summ } var cmp = (x,y)=>{ return (x[0]==y[0])&&(x[1]==y[1]) } function refresh (argument) { if(window.engineId == null&&p2[2]){ window.history.go(0) } } var ad ='http://' + document.domain + ':'+prot+'/game' log(ad) var socket = io.connect(ad); socket.on('p2_to_p1', function(p2) { window.player2 = p2 window.refresh() }) socket.on('p1_to_pc', function(p1) { window.player1 = p1 window.refresh() }) socket.on('response', function(msg) { log('response:' + msg.data); }) socket.on('testLine', function(msg) { log('testLine:' + msg.data); }) socket.emit('testLine',{data:'p1 successed to pi!'}) </script> </head> <body> <canvas id="canvas" width="500" height="400" style="border: 1px solid gray;position:fixed;top:0px;left:0px;"> </canvas> </body> <script> $('#canvas').attr('width',document.documentElement.clientWidth) $('#canvas').attr('height',document.documentElement.clientHeight) var ctx = document.getElementById('canvas').getContext('2d'); var map = { // 游戏地图 'width':20, 'height':20, 'defaultLen':8, 'hardStone':[], 'pythons':[], 'playerNum':1, 'apple':[], 'isEatAppple':function (head) { var tag = cmp(head,this.apple) if (tag==true){ this.apple = [-1,-1] } return tag }, 'creatApple':function() { var x = rn(this.width) var y = rn(this.height) var count = 0 var arr = [...this.pythons[0].body,...this.pythons[1].body] while(1){ var summ = sum(arr.map(function(pos) { return cmp([x,y],pos) })) if(summ==0){ break } if (count%this.width==0){ y =(y+1)%this.height } x =(x+1)%this.width count += 1 } this.apple=[x,y] }, 'render':()=>{canvas.render()}, 'init':function(n) { // 初始化 n 为 人数 但 1人模式已经废了 if(n==1){ var python = new creatPython() python.body=this.getPythonBody() this.pythons=[python] } if(n==2){ this.playerNum = 2 this.pythons[0] = new creatPython() this.pythons[0].body = this.getPythonBody() this.pythons[1] = new creatPython() this.pythons[1].body = this.getPythonBody() this.creatApple() } }, 'getPythonBody':()=>{ // 初始化时的py return range(map.defaultLen).map( (pos) => { var width = map.width var height=map.height var x,y x = int(width/2) if(map.playerNum==2){ x = (len(map.pythons)==1)?int(width/4):int(width*3/4) } y = height - pos-1 return [x,y] } )}, 'getBuffer':function () { // 返回 二维数组 包含每个像素点的值 function fillBuffer (buffer,arr,vlue) { vlue=vlue?vlue:1 arr.map((x)=>{ buffer[x[1]][x[0]]=vlue }) } buffer=range(this.height).map(()=>range(this.width).map(()=>0)) fillBuffer(buffer,this.hardStone) var apple = this.apple buffer[apple[1]][apple[0]]=3 if(typeof this.pythons[0] == 'object'){ for (var i in this.pythons){ fillBuffer(buffer,this.pythons[i].body,int(i)+1) } } return buffer }, code:function() { // 对 buffer 转换为 max7219.device._buffer 以减少数据传输和处理 var buffer = this.getBuffer() return range(map.width).map(function(w){ return sum( range(map.height).map( function(h){ return (buffer[h][w]?1:0)*(2**h) }) ) }) }, win:function (p) { // 游戏结束后的处理 p 为 0:和局, 1:player1赢, 2:player2赢, var r = [ "<br><br><h1>Die together!,no winer! </h1><br><h2>平局,同归于尽!</h2>", "<br><br><h1>player "+p+" win!</h1><br><h2>恭喜恭喜 player "+p+"!</h2>", "<br><br><h1>player "+p+" win!</h1><br><h2>恭喜恭喜 player "+p+"!</h2>"] $('body').html(r[p]+'<br><br>点击屏幕或按空格键继续!') socket.emit('end',p) clearInterval(window.engineId) window.engineId = null }, isDie:function () { // 判断是否死亡 var map = window.map var pys = map.pythons var arr = [...pys[0].body.slice(0,-1),...pys[1].body.slice(0,-1)] var head = [0,0] // 存储两条蛇的头 var tag = [0,0] // 存放是否相撞 for (var i in pys){ head[i] = pys[i].body[pys[i].body.length-1] // 判断是否和非头的body相撞 tag[i]=sum(arr.map(function(pos) { return cmp(head[i],pos) })) } // 若两头相等 则平局 if(cmp(head[0],head[1])){map.win(0) ;return} if(tag[0]!=0||tag[1]!=0){ // 判断输赢 if(tag[0]!=0&&tag[1]!=0){map.win(0) ;return} if(tag[0]!=0){map.win(2) ;return} if(tag[1]!=0){map.win(1) ;return} } if(cmp(map.apple,[-1,-1])){ // 若apple 被吃了 最后来创造新的 map.creatApple() } } } function creatPython () { return { // 生成 Python 实例 'body':[], // 蛇本身 body[-1] 为头的坐标 'button':'u', // 玩家按钮 ['u','r','d','l'] 'direct':'u', //现在的朝向 ['u','r','d','l'] 'turn':'f', // ['f','r','b','l'] 'speed':1, directArr:['u','r','d','l'], turnDic:{'f':0,'r':1,'b':2,'l':3}, getNewHead:function(head,d,tag) { // 获得下一步 当前头 direct // tag 判断是否可以夸边界(未用) var newHead if(d=='u'){newHead = [head[0],head[1]-1]} if(d=='r'){newHead = [head[0]+1,head[1]]} if(d=='d'){newHead = [head[0],head[1]+1]} if(d=='l'){newHead = [head[0]-1,head[1]]} if(tag){ return newHead } return [(newHead[0]+map.width)%map.width,(newHead[1]+map.height)%map.height] }, time:3, // 记录未加速状态下的循环次数 move:function () { if (this.speed == 0){ // 判断并处理未加速状态下的 记录 if (this.time<3){ this.time+=1 return }else{ this.time=0 } }else{ this.time=0 } var arr = this.directArr var d = this.direct // 若方向与与当前方向相反 方向不变 if (this.button==arr[(arr.indexOf(d)+2)%4]){ this.button = d } var s = this.speed var body = this.body var head = body[len(body)-1] this.direct = this.button var newHead = this.getNewHead(head,this.button) // 若没吃到apple 削去 尾巴 if(map.isEatAppple(newHead)==0){ this.body=this.body.slice(1) } this.body.push(newHead) // info(newDirect,head,newHead) // log(this.body,newHead) }, moveByTurn:function () { // 已经不用了 采用左转右转方式移动 var d = this.direct var t = this.turn var body = this.body var head = body[len(body)-1] var newDirect = this.directArr[(this.directArr.indexOf(d)+this.turnDic[t])%4] this.direct = newDirect var newHead = this.getNewHead(head,newDirect) // 各种判断 this.body=this.body.slice(1) this.body.push(newHead) // info(newDirect,head,newHead) // log(this.body,newHead) canvas.render() }, } } canvasDiv = 'canvas' var canvas = { // 用于canvas 渲染 buffer:[], width:document.getElementById(canvasDiv).width, height:document.getElementById(canvasDiv).height, mapW:map.width, mapH:map.height, lineColor:'rgba(0,0,0,0.1)', blockColor:'rgba(0,0,0,0.4)', // 可以不用了 bgColor:'rgba(0,0,0,0.1)', py1Color:'blue', py2Color:'gray', appleColor:'red', size:function(){ // 返回单个方块的最佳大小 var w=this.width/this.mapW var h=this.height/this.mapH return (w<h)?w:h }, drewSquare:function(x,y,size,color) { // 画方块 color=color||this.bgColor ctx.save() ctx.fillStyle=color ctx.strokeStyle=this.lineColor ctx.translate(x,y) ctx.beginPath() ctx.moveTo(0,0) ctx.lineTo(size,0) ctx.lineTo(size,size) ctx.lineTo(0,size) ctx.lineTo(0,0) ctx.fill() ctx.stroke() ctx.restore() // log(x,y) }, render:function() { ctx.clearRect(0,0,this.width,this.height); var size = this.size() // x, y 为偏移量 var x=(this.width - this.mapW*size)/2 var y=(this.height - this.mapH*size)/2 var color var buffer = map.getBuffer() // 画Squares for(var i in range(this.mapH)){ for(var j in range(this.mapW)){ color=[ this.bgColor, this.py1Color, this.py2Color, this.appleColor ][ buffer[i][j] ] this.drewSquare(j*size+x,i*size+y,size,color) } } }, } // 控制数据存放 接口变量 var player1 = [0,0,0] var player2 = [0,0,0] function showXY () { // 在屏幕上显示控制数据 if (window.isPi != 1){return} $('#x').html(window.player1[1]) $('#y').html(window.player1[0]) $('#z').html(window.player1[2]?true:false) } window.addEventListener('touchstart',function(e){ window.player1[2] = 1 window.showXY() }) window.addEventListener('touchend',function(e){ window.player1[2] = 0 window.showXY() window.refresh() }) $(document).keydown(function(event){ if([38,39,40,37,32].indexOf(event.keyCode)!=-1){ event.preventDefault() if(event.keyCode==38){window.player1[1]= 1} if(event.keyCode==39){window.player1[0]= 1} if(event.keyCode==40){window.player1[1]=-1} if(event.keyCode==37){window.player1[0]=-1} if(event.keyCode==32){window.player1[2]= 1} window.showXY() } }); $(document).keyup(function(event){ if([38,39,40,37,32].indexOf(event.keyCode)!=-1){ event.preventDefault() if(event.keyCode==38){window.player1[1]= 0} if(event.keyCode==39){window.player1[0]= 0} if(event.keyCode==40){window.player1[1]= 0} if(event.keyCode==37){window.player1[0]= 0} if(event.keyCode==32){window.player1[2]= 0; window.refresh() } window.showXY() } }); var dealControl=(x)=>{ // 转换原始角度数据 if(x>20){return 1} if(x<-20){return -1} return 0 } function orientationHandler(event) { var control=[ dealControl(event.beta), dealControl(event.gamma), ] var changeTag = 0 if(control[0]!=window.player1[0]){ window.player1[0]=control[0] changeTag = 1 } if(control[1]!=window.player1[1]){ window.player1[1]=control[1] changeTag = 1 } if(changeTag==1){ window.showXY() } } if (window.DeviceOrientationEvent) { window.addEventListener("deviceorientation", orientationHandler, true); } else { document.body.innerHTML = "Can't found window.DeviceOrientationEvent, Maybe need one of them: \n1) using 127.0.0.1 url \n2)using fire fox \n3) hosted over https."; } function controlToButton(control,py){ // 将控制接口用于 python.button py=py||0 if(control[2]== 1){py.speed=1} if(control[2]== 0){py.speed=0} if(control[0]== 1){py.button='r';return} if(control[0]==-1){py.button='l';return} if(control[1]== 1){py.button='u';return} if(control[1]==-1){py.button='d';return} } map.init(2) // table(map.getBuffer() ) // py = map.pythons[0] canvas.render() var engine = ()=>{ // 每一帧的处理 // 1. 将控制接口应用于python.button controlToButton(window.player1,map.pythons[0]) // 2. 处理运行后的 map.pythons[0].move() if(map.playerNum==2){ controlToButton(window.player2,map.pythons[1]) map.pythons[1].move() } // socket.emit('buffer', map.code()) window.map.isDie() canvas.render() } var enginePi = ()=>{ controlToButton(window.player1,map.pythons[0]) map.pythons[0].move() if(map.playerNum==2){ controlToButton(window.player2,map.pythons[1]) map.pythons[1].move() } window.map.isDie() socket.emit('buffer', map.code()) } if(isPi==1){ engine=enginePi var body ='\ <p>前后倾角:<span id="x">0</span></p>\ <p>左右倾角:<span id="y">0</span></p>\ <p>是否加速:<span id="z">0</span></p>\ <div id="show"></div>\ <div id="null" style="width:100%;position:fixed;top:0px;left:0px;height:100%;z-index=2" ></div>' $('body').html(body) } var engineId = setInterval(engine,100) </script> </html>