import 'es6-shim' ; import * as config from '~/common/config' ; import * as utils from '~/common/utils' ; import { Base } from '~/element/Base' ; import { Food } from '~/element/Food' ; import { CustomSnake , Movement , Snake } from '~/element/Snake' ; import { GameMap } from '~/framework/GameMap' ; import { Observer } from '~/framework/Observer' ; if ( module && module . hot ) { module . hot . accept ( ( ) => { location . reload ( ) ; } ) ; } const raf = window . requestAnimationFrame || window . webkitRequestAnimationFrame ; const canvas = document . getElementById ( 'cas' ) as HTMLCanvasElement ; let isInit = false ; let playerId ; const isObserver = window . location . href . indexOf ( 'observer=true' ) >= 0 ; const vWidth = window . innerWidth ; const vHeight = window . innerHeight ; export const gameMap = new GameMap ( canvas , vWidth , vHeight ) ; let player ; const mouseCoords = { } ; const snakes = new Map ( ) ; const enum KeyCodes { W = 87 , S = 83 , A = 65 , UP = 38 , RIGHT = 39 , DOWN = 40 , LEFT = 37 } const foods = [ ] ; const ws = new WebSocket ( `ws://${ process . env . LOCAL_IP || '127.0.0.1' }:${ config . socketPort }` ) ; ws . binaryType = 'arraybuffer' ; ws . onopen = ( ) => { sendData ( config . CMD_INIT , utils . VIEW_TYPE , { width : vWidth , height : vHeight , } ) ; } ; ws . onerror = ( ) => { console . log ( 'error' ) ; } ; ws . onclose = ( ) => { if ( isInit ) { return ; } const x = ~ ~ ( Math . random ( ) * ( config . MAP_WIDTH - 100 ) + 100 / 2 ) ; const y = ~ ~ ( Math . random ( ) * ( config . MAP_WIDTH - 100 ) + 100 / 2 ) ; initGame ( x , y ) ; } ; ws . onmessage = ( e ) => { let data ; const buf = e . data ; if ( buf instanceof ArrayBuffer ) { data = utils . decode ( buf ) ; } else { data = JSON . parse ( buf ) ; } let packet ; switch ( data . opt ) { case config . CMD_INIT_ACK : packet = data . data [ 0 ] . packet ; playerId = packet . id ; initGame ( packet . x , packet . y ) ; break ; case config . CMD_SYNC_OTHER_COORD : if ( ! isInit ) { return ; } let snake ; data . data . forEach ( ( item ) => { packet = item . packet ; if ( item . type === utils . SNAKE_TYPE ) { if ( playerId === packet . id ) { return ; } else if ( snakes . has ( packet . id ) ) { snake = snakes . get ( packet . id ) as CustomSnake ; const movement = new Movement ( packet . x , packet . y , packet . speed , packet . angle ) ; snake . sync ( packet . size , packet . length , movement ) ; } else { snake = new CustomSnake ( { x : packet . x , y : packet . y , angle : packet . angle , size : packet . size , length : packet . length , fillColor : '#666' , } ) ; snakes . set ( packet . id , snake ) ; } } else if ( item . type === utils . FOOD_TYPE ) { } } ) ; break ; case config . CMD_LOSE_CONNECT : packet = data . data [ 0 ] . packet ; if ( snakes . has ( packet . id ) ) { snakes . delete ( packet . id ) ; } break ; default : break ; } } ; /**
 * game init
 */ function initGame ( x , y ) { isInit = true ; if ( isObserver ) { player = new Observer ( gameMap . width / 2 , gameMap . height / 2 ) ; } else { player = new Snake ( { x , y , size : 30 , length : 280 , angle : Math . random ( ) * 2 * Math . PI , fillColor : '#000' , } ) ; } binding ( ) ; animate ( ) ; } /**
 * collision check
 */ function collision ( dom , dom2 , isRect ? ) { const disX = dom . x - dom2 . x ; const disY = dom . y - dom2 . y ; const dw = dom . width + dom2 . width ; if ( Math . abs ( disX ) > dw || Math . abs ( disY ) > dom . height + dom2 . height ) { return false ; } return isRect ? true : ( Math . hypot ( disX , disY ) < dw / 2 ) ; } let timeout = 0 ; let time = + new Date ( ) ; function animate ( ) { const newTime = + new Date ( ) ; const snakePlayer = player instanceof Snake ? player as Snake : null ; if ( newTime - time > timeout ) { time = newTime ; gameMap . update ( player , ( ) => { snakes . forEach ( ( snake ) => { snake . update ( ) ; } ) ; player . update ( ) ; if ( snakePlayer ) { foods . forEach ( ( food ) => { food . update ( ) ; if ( ! food . visible || ! collision ( snakePlayer , food ) ) { return ; } const added = snakePlayer . eat ( food ) ; foods . splice ( foods . indexOf ( food ) , 1 ) ; const newScale = gameMap . scale + added / ( snakePlayer . width * 4 ) ; if ( newScale < 1.4 ) { gameMap . setToScale ( newScale ) ; } } ) ; } } ) ; if ( snakePlayer && playerId ) { sendData ( config . CMD_SYNC_MAIN_COORD , utils . SNAKE_TYPE , { id : playerId , size : snakePlayer . width , speed : snakePlayer . speed , length : snakePlayer . length , x : snakePlayer . x , y : snakePlayer . y , } ) ; } } raf ( animate ) ; } function sendData ( opt , type , packet ) { ws . send ( utils . encode ( { opt , data : { type , packet } , } ) ) ; } /**
 * event binding
 */ function binding ( ) { function mousemove ( e ) { e . preventDefault ( ) ; if ( ( e as TouchEvent ) . touches ) { mouseCoords . x = ( e as TouchEvent ) . touches [ 0 ] . pageX ; mouseCoords . y = ( e as TouchEvent ) . touches [ 0 ] . pageY ; } else { const evt = e as MouseEvent || ( window . event as MouseEvent ) ; mouseCoords . x = evt . clientX ; mouseCoords . y = evt . clientY ; } const nx = ( mouseCoords . x + gameMap . view . x ) * gameMap . scale ; const ny = ( mouseCoords . y + gameMap . view . y ) * gameMap . scale ; if ( ! isObserver ) { player . moveTo ( nx , ny ) ; } } if ( navigator . userAgent . match ( /(iPhone|iPod|Android|ios)/i ) ) { window . addEventListener ( 'touchstart' , mousemove ) ; window . addEventListener ( 'touchmove' , mousemove ) ; if ( player instanceof Observer ) { window . addEventListener ( 'touchend' , ( ) => { ( player as Observer ) . stop ( ) ; } ) ; } } else { window . addEventListener ( 'mousemove' , mousemove ) ; if ( player instanceof Snake ) { const pl = player as Snake ; window . addEventListener ( 'mousedown' , ( ) => { pl . speedUp ( ) ; } ) ; window . addEventListener ( 'mouseup' , ( ) => { pl . speedDown ( ) ; } ) ; } else { window . onmousedown = ( e ) => { let startX = e . pageX ; let startY = e . pageY ; window . onmousemove = ( e ) => { const newStartX = e . pageX ; const newStartY = e . pageY ; const distanceX = newStartX - startX ; const distanceY = newStartY - startY ; player . x += - distanceX ; player . y += - distanceY ; startX = newStartX ; startY = newStartY ; } ; window . onmouseup = ( ) => { window . onmousemove = null ; } ; } ; window . addEventListener ( 'keyup' , ( e ) => { switch ( e . keyCode ) { case KeyCodes . W : gameMap . setToScale ( gameMap . scale + 0.2 ) ; break ; case KeyCodes . S : gameMap . setToScale ( gameMap . scale - 0.2 ) ; break ; case KeyCodes . A : gameMap . setToScale ( 1 ) ; break ; case KeyCodes . UP : timeout = timeout < 5 ? 0 : ( timeout - 5 ) ; break ; case KeyCodes . DOWN : timeout += 5 ; break ; default : break ; } } ) ; } } }