Created
November 16, 2016 13:48
-
-
Save hakatashi/5e09112829299313aad6c466a1566b48 to your computer and use it in GitHub Desktop.
TSG 第12回Web分科会 参考実装
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Robot Fight</title> | |
<script src="/socket.io/socket.io.js"></script> | |
<script src="https://code.jquery.com/jquery-3.1.1.js"></script> | |
<style> | |
.field { | |
width: 500px; | |
height: 500px; | |
margin: 50px auto; | |
background: #ddd; | |
position: relative; | |
} | |
.robot { | |
position: absolute; | |
border-right: 20px solid transparent; | |
border-left: 20px solid transparent; | |
border-bottom: 40px solid red; | |
} | |
.robot.blue { | |
border-bottom-color: blue; | |
} | |
.robot.red { | |
border-bottom-color: red; | |
} | |
</style> | |
<script> | |
$(() => { | |
const socket = io(); | |
const width = 500; | |
const height = 500; | |
const moves = { | |
37: {x: -1, y: 0}, | |
38: {x: 0, y: -1}, | |
39: {x: 1, y: 0}, | |
40: {x: 0, y: 1}, | |
}; | |
const pressedKeys = new Map(); | |
const createRobot = (id, team, x, y, direction) => { | |
$('.field').append($('<div/>', { | |
'class': `robot ${team}`, | |
attr: { | |
'data-id': id, | |
}, | |
})); | |
moveTo(id, x, y, direction); | |
}; | |
const destroyRobot = (id) => { | |
$(`.robot[data-id="${id}"]`).remove(); | |
}; | |
let x = Math.random() * width; | |
let y = Math.random() * height; | |
let direction = Math.floor(Math.random() * 4); | |
const selfID = Math.floor(Math.random() * 1000000); | |
const {team, speed} = (() => { | |
if (Math.random() < .5) { | |
return {team: 'red', speed: 4}; | |
} else { | |
return {team: 'blue', speed: 8}; | |
} | |
})(); | |
let killed = false; | |
const moveTo = (id, x, y, direction) => { | |
const rotation = (direction - 1) * 90; | |
$(`.robot[data-id="${id}"]`).css({ | |
transform: `translate(calc(${x}px - 50%), calc(${y}px - 50%)) rotate(${rotation }deg)`, | |
}); | |
}; | |
$('.robot.self').attr('data-id', selfID).addClass(team); | |
moveTo(selfID, x, y, direction); | |
// キー情報の記録 | |
$(window).keydown((event) => { | |
pressedKeys.set(event.which, true); | |
}); | |
$(window).keyup((event) => { | |
pressedKeys.set(event.which, false); | |
}); | |
// 移動する | |
setInterval(() => { | |
[37, 38, 39, 40].forEach((keycode) => { | |
if (pressedKeys.get(keycode)) { | |
const move = moves[keycode]; | |
x += move.x * speed; | |
y += move.y * speed; | |
x = Math.max(0, Math.min(x, width)); | |
y = Math.max(0, Math.min(y, height)); | |
direction = keycode - 37; | |
moveTo(selfID, x, y, direction); | |
} | |
}); | |
}, 20); | |
// 位置データを送信する | |
setInterval(() => { | |
if (!killed) { | |
socket.emit('position', {selfID, x, y, direction, team}); | |
} | |
}, 100); | |
let robotList = new Set(); | |
// ロボットが増えたら何かする | |
socket.on('robots', (data) => { | |
const robots = new Map(data); | |
for (const [id, robot] of robots.entries()) { | |
if (id !== selfID) { | |
if (robotList.has(id)) { | |
moveTo(id, robot.x, robot.y, robot.direction); | |
} else { | |
createRobot(id, robot.team, robot.x, robot.y, robot.direction); | |
} | |
} | |
} | |
for (const id of robotList.values()) { | |
if (!robots.has(id)) { | |
destroyRobot(id); | |
if (id === selfID) { | |
killed = true; | |
} | |
} | |
} | |
robotList = new Set(robots.keys()); | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<div class="field"> | |
<div class="robot self" direction="1"></div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const http = require('http'); | |
const socketIO = require('socket.io'); | |
const app = http.createServer((req, res) => { | |
const stat = fs.statSync('robot.html'); | |
res.writeHead(200, { | |
'Content-Type': 'text/html', | |
'Content-Length': stat.size, | |
}); | |
fs.createReadStream('robot.html').pipe(res); | |
}); | |
const currentRobotIDs = new Map(); | |
const io = socketIO(app); | |
io.on('connection', (socket) => { | |
let id = null; | |
// 現在の位置が更新されたら | |
socket.on('position', ({selfID, x, y, direction, team}) => { | |
id = selfID; | |
currentRobotIDs.set(id, {x, y, direction, team}); | |
}); | |
// 接続が切断されたら | |
socket.on('disconnect', () => { | |
currentRobotIDs.delete(id); | |
}); | |
}); | |
const distance = (A, B) => ( | |
(A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) | |
); | |
// positionデータを全クライアントに送る | |
setInterval(() => { | |
// 衝突判定 | |
for (const [idA, robotA] of currentRobotIDs.entries()) { | |
if (robotA.team === 'red') { | |
for (const [idB, robotB] of currentRobotIDs.entries()) { | |
if (robotB.team === 'blue' && distance(robotA, robotB) < 1600) { | |
currentRobotIDs.delete(idB); | |
} | |
} | |
} | |
} | |
io.emit('robots', Array.from(currentRobotIDs.entries())); | |
}, 100); | |
app.listen(8080, () => { | |
console.log('Listening localhost:8080...'); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment