Created
February 19, 2013 16:55
-
-
Save takatama/4987698 to your computer and use it in GitHub Desktop.
TypeScript入門 ぷよ編
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
ぷよ http://ja.wikipedia.org/wiki/%E3%81%B7%E3%82%88%E3%81%B7%E3%82%88 | |
<左側のプレーヤー> | |
a 左移動 | |
d 右移動 | |
s 右回転 | |
x 高速落下 | |
<右側のプレーヤー> | |
左右キー 移動 | |
上キー 右回転 | |
下キー 高速落下 | |
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
<div id="player1" style="float:left"> | |
<canvas id="canvas1" width="200" height="340"></canvas> | |
<p> | |
a 左, d 右, s 回転, x 落下 | |
</p> | |
</div> | |
<div id="space" style="float:left"> | |
| |
</div> | |
<div id="player2" style="float:left"> | |
<canvas id="canvas2" width="200" height="340"></canvas> | |
<p> | |
←左, →右, ↑回転, ↓落下 | |
</p> | |
</div> | |
<br style="clear:left"> | |
<button id="start">start</button> | |
<button id="stop">stop</button> | |
<button id="restart">restart</button> | |
<button id="oneplay">一人で遊ぶ</button> | |
<button id="twoplay">二人で遊ぶ</button> |
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
//TODO ちぎれたときのコンボの数え方が間違ってる? | |
class Field { | |
cellSize: number; | |
context; | |
maxX: number = 6; | |
maxY: number = 12; | |
topPuyos: number[] = []; | |
puyoPair: PuyoPair; | |
nextPair: PuyoPair; | |
fixedPuyos: Puyo[] = []; | |
timer: number; | |
combo = -1; | |
oppositeField: Field; | |
jammers: Puyo[] = []; | |
keyController = null; | |
message: string; | |
messageColor: string; | |
constructor(public canvas: HTMLCanvasElement) { | |
this.context = canvas.getContext('2d'); | |
this.cellSize = canvas.width / (this.maxX + 1); | |
this.init(); | |
} | |
init(): Field { | |
var i; | |
this.stop(); | |
this.puyoPair = null; | |
this.nextPair = null; | |
this.fixedPuyos = []; | |
this.jammers = []; | |
this.combo = -1; | |
for (i = 0; i < this.maxX; i++) { | |
this.topPuyos[i] = this.maxY; | |
} | |
if (this.keyController) { | |
document.removeEventListener('keydown', this.keyController, false); | |
this.keyController = null; | |
} | |
this.nextPuyoPair(); | |
return this; | |
} | |
start(): Field { | |
var that = this; | |
if (this.timer) { | |
return; | |
} | |
this.draw(); | |
this.timer = setInterval(function () { | |
var hit = false; | |
that.puyoPair.down(); | |
that.draw(); | |
hit = that.hitting(); | |
that.combine(); | |
if (hit) { | |
that.nextPuyoPair(); | |
that.draw(); | |
} | |
}, 1000); | |
if (!this.keyController) { | |
this.keyController = this.createKeyController(); | |
document.addEventListener('keydown', this.keyController, false); | |
} | |
return this; | |
} | |
stop(): Field { | |
clearInterval(this.timer); | |
this.timer = null; | |
return this; | |
} | |
clear(): Field { | |
this.init(); | |
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); | |
return this; | |
} | |
draw(): void { | |
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); | |
this.context.strokeRect(0, 0, this.canvas.width - this.cellSize, this.canvas.height); | |
if (this.puyoPair) { | |
this.puyoPair.draw(this.context, this.cellSize); | |
} | |
var that = this; | |
this.fixedPuyos.forEach(function (puyo) { | |
puyo.draw(that.context, that.cellSize); | |
}); | |
this.nextPair.draw(this.context, this.cellSize); | |
this.drawString(); | |
} | |
hitting(): bool { | |
if (this.puyoPair.inPuyo.y > this.topPuyos[this.puyoPair.inPuyo.x] - 2 || | |
this.puyoPair.outPuyo.y > this.topPuyos[this.puyoPair.outPuyo.x] - 2 ) { | |
this.combo = -1; | |
this.fixPuyoPairs(); | |
return true; | |
} | |
return false; | |
} | |
fixPuyoPairs(): void { | |
var belowPuyo = this.puyoPair.inPuyo, | |
abovePuyo = this.puyoPair.outPuyo, | |
temp; | |
if (belowPuyo.y < abovePuyo.y) { | |
temp = belowPuyo; | |
belowPuyo = abovePuyo; | |
abovePuyo = temp; | |
} | |
this.fixAtTop(belowPuyo); | |
this.fixAtTop(abovePuyo); | |
} | |
fixAtTop(puyo: Puyo) { | |
puyo.y = this.topPuyos[puyo.x] - 1; | |
this.fixedPuyos.push(puyo); | |
this.topPuyos[puyo.x] -= 1; | |
if (this.topPuyos[puyo.x] <= 0) { | |
this.lose(); | |
} | |
} | |
lose(): void { | |
this.stop(); | |
this.displayString('Lose', 'blue'); | |
if (this.oppositeField) { | |
this.oppositeField.stop(); | |
this.oppositeField.displayString('Win', 'red'); | |
} | |
} | |
displayString(message: string, color: string): void { | |
this.message = message; | |
this.messageColor = color; | |
this.draw(); | |
} | |
drawString(): void { | |
if (this.message) { | |
var oldStyle = this.context.strokeStyle; | |
this.context.strokeStyle = this.messageColor; | |
this.context.textAlign = 'center'; | |
this.context.font = 'normal 20pt Calibri'; | |
this.context.strokeText(this.message, this.cellSize * this.maxX / 2, this.cellSize * this.maxY / 2); | |
this.context.strokeStyle = oldStyle; | |
} | |
} | |
randomPuyoPair(): PuyoPair { | |
this.randomColor(); | |
var pair = new PuyoPair(this, new Puyo(this.maxX, 1, this.randomColor()), new Puyo(this.maxX, 0, this.randomColor())); | |
return pair; | |
} | |
randomColor(): string { | |
switch (Math.floor(Math.random() * 4)) { | |
case 0: | |
return "blue"; | |
case 1: | |
return "orange"; | |
case 2: | |
return "green"; | |
case 3: | |
return "purple"; | |
} | |
} | |
nextPuyoPair(): void { | |
if (!this.nextPair) { | |
this.nextPair = this.randomPuyoPair(); | |
} | |
this.puyoPair = this.nextPair; | |
// this.puyoPair.left().left().left(); | |
if(this.fixedPuyo(3, 0) || this.fixedPuyo(3, 1)) { | |
this.lose(); | |
} | |
this.puyoPair.inPuyo.x = 3; | |
this.puyoPair.outPuyo.x = 3; | |
this.nextPair = this.randomPuyoPair(); | |
} | |
createKeyController() { | |
return null; | |
} | |
combine(): void { | |
var visitedPuyos: Puyo[] = [], | |
visitor = new CombineVisitor(this, visitedPuyos); | |
this.fixedPuyos.forEach(function (puyo) { | |
puyo.accept(visitor); | |
}); | |
this.deleteCombinedPuyoPairs(visitor.combinedPuyoPairs); | |
} | |
fixedPuyo(x: number, y: number): Puyo { | |
var i, len; | |
if (x < 0 || x >= this.maxX || y < 0 || y >= this.maxY) { | |
return null; | |
} | |
for (i = 0, len = this.fixedPuyos.length; i < len; i++) { | |
if (this.fixedPuyos[i].x == x && this.fixedPuyos[i].y === y) { | |
return this.fixedPuyos[i]; | |
} | |
} | |
return null; | |
} | |
deleteCombinedPuyoPairs(pairs: PuyoPair[][]): void { | |
var i, j, len; | |
this.combo++; | |
for (i = 0, len = pairs.length; i < len; i++) { | |
var deletingPuyos = this.puyos(pairs[i]); | |
for (j = 0; j < deletingPuyos.length; j++) { | |
this.deleteFixedPuyo(deletingPuyos[j]); | |
} | |
this.shiftDownFixedPuyos(deletingPuyos); | |
this.updateTopPuyos(deletingPuyos); | |
var jammer = deletingPuyos.length / 2 * (this.combo + 1); | |
if (this.oppositeField) { | |
this.oppositeField.addJammer(jammer); | |
} | |
this.draw(); | |
} | |
} | |
puyos(pairs: PuyoPair[]) { | |
var i, j, puyos = []; | |
for (i = 0; i < pairs.length; i++) { | |
this.add(puyos, pairs[i].inPuyo); | |
this.add(puyos, pairs[i].outPuyo); | |
} | |
return puyos; | |
} | |
add(arr, obj): void { | |
var i; | |
for (i = 0; i < arr.length; i++) { | |
if (arr[i] === obj) { | |
return; | |
} | |
} | |
arr.push(obj); | |
} | |
deleteFixedPuyo(puyo: Puyo): void { | |
var i, len; | |
for (i = 0, len = this.fixedPuyos.length; i < len; i++) { | |
if (this.fixedPuyos[i] === puyo) { | |
this.fixedPuyos.splice(i, 1); | |
return; | |
} | |
} | |
} | |
shiftDownFixedPuyos(deletingPuyos: Puyo[]): void { | |
var i, len, newPuyos = []; | |
for(i = 0, len = this.fixedPuyos.length; i < len; i++) { | |
this.fixedPuyos[i].y += this.countBelowSpace(this.fixedPuyos[i].x, this.fixedPuyos[i].y, deletingPuyos); | |
} | |
} | |
countBelowSpace(x: number, y: number, deletingPuyos: Puyo[]): number { | |
var i, len, count = 0; | |
for (i = 0, len = deletingPuyos.length; i < len; i++) { | |
if (deletingPuyos[i].x === x && deletingPuyos[i].y > y) { | |
count++; | |
} | |
} | |
return count; | |
} | |
updateTopPuyos(deletingPuyos: Puyo[]): void { | |
var i; | |
for (i = 0; i < this.maxX; i++) { | |
var deleteCount = this.countBelowSpace(i, this.topPuyos[i] - 1, deletingPuyos); | |
this.topPuyos[i] += deleteCount; | |
} | |
} | |
addJammer(count: number): void { | |
var i; | |
for (i = 0; i < count; i++) { | |
var x = Math.floor(Math.random() * this.maxX); | |
this.jammers.push(new Puyo(x, 0, "gray")); | |
} | |
this.processJammer(); | |
} | |
processJammer(): void { | |
var i; | |
for (i = 0; i < this.jammers.length; i++) { | |
this.fixAtTop(this.jammers[i]); | |
} | |
this.jammers = []; | |
this.draw(); | |
} | |
} | |
class AlphabetField extends Field { | |
constructor(public canvas: HTMLCanvasElement) { | |
super(canvas); | |
} | |
createKeyController() { | |
var a = 65, w = 87, d = 68, s = 83, x = 88, z = 90; | |
var field = this; | |
return function (event) { | |
var chCode = (event.keyCode) ? event.keyCode : event.charCode; | |
switch(chCode) { | |
case w: | |
case s: | |
field.puyoPair.rotateRight(); | |
field.draw(); | |
break; | |
case d: | |
field.puyoPair.right(); | |
field.draw(); | |
break; | |
case a: | |
field.puyoPair.left(); | |
field.draw(); | |
break; | |
case z: | |
case x: | |
field.puyoPair.down(); | |
field.draw(); | |
break; | |
} | |
}; | |
} | |
} | |
class ArrowField extends Field { | |
constructor(public canvas: HTMLCanvasElement) { | |
super(canvas); | |
} | |
createKeyController() { | |
var left = 37, up = 38, right = 39, down = 40; | |
var field = this; | |
return function (event) { | |
var chCode = (event.keyCode) ? event.keyCode : event.charCode; | |
switch(chCode) { | |
case up: | |
field.puyoPair.rotateRight(); | |
field.draw(); | |
break; | |
case right: | |
field.puyoPair.right(); | |
field.draw(); | |
break; | |
case left: | |
field.puyoPair.left(); | |
field.draw(); | |
break; | |
case down: | |
field.puyoPair.down(); | |
field.draw(); | |
break; | |
} | |
}; | |
} | |
} | |
class CombineVisitor { | |
public combinedPuyoPairs: PuyoPair[][] = []; | |
constructor(private field: Field, private visited: Puyo[]) { | |
} | |
visit(puyo: Puyo): void { | |
var pairs: PuyoPair[] = []; | |
this.travel(puyo, pairs); | |
if (pairs.length >= 3) { | |
this.combinedPuyoPairs.push(pairs); | |
} | |
} | |
travel(puyo: Puyo, pairs: PuyoPair[]): void { | |
if (this.isVisited(puyo)) { | |
return; | |
} | |
this.visited.push(puyo); | |
this.pushPuyoPairIfCombined(puyo, this.field.fixedPuyo(puyo.x, puyo.y - 1), pairs); | |
this.pushPuyoPairIfCombined(puyo, this.field.fixedPuyo(puyo.x + 1, puyo.y), pairs); | |
this.pushPuyoPairIfCombined(puyo, this.field.fixedPuyo(puyo.x, puyo.y + 1), pairs); | |
this.pushPuyoPairIfCombined(puyo, this.field.fixedPuyo(puyo.x - 1, puyo.y), pairs); | |
} | |
isVisited(puyo: Puyo): bool { | |
var i, len; | |
for (i = 0, len = this.visited.length; i < len; i++) { | |
if (this.visited[i] === puyo) { | |
return true; | |
} | |
} | |
return false; | |
} | |
private pushPuyoPairIfCombined(puyoA: Puyo, puyoB: Puyo, pairs: PuyoPair[]): void { | |
if (!puyoA || !puyoB) { | |
return; | |
} | |
if (this.isVisited(puyoB)) { | |
return; | |
} | |
if (this.isCombinedTo(puyoA, puyoB)) { | |
pairs.push(new PuyoPair(this.field, puyoA, puyoB)); | |
this.travel(puyoB, pairs); | |
} | |
} | |
isCombinedTo(puyoA: Puyo, puyoB: Puyo): bool { | |
if (puyoA.color === 'gray' || puyoB.color === 'gray') { | |
return false; | |
} | |
if (puyoA.color === puyoB.color) { | |
return true; | |
} | |
return false; | |
} | |
} | |
class Puyo { | |
constructor(public x: number, public y: number, public color: string) { | |
} | |
draw(context, cellSize: number) { | |
var radius = cellSize / 3; | |
context.beginPath(); | |
context.fillStyle = this.color; | |
context.arc(this.xPx(cellSize), this.yPx(cellSize), radius, 0, Math.PI*2, false); | |
context.fill(); | |
} | |
xPx(cellSize: number): number { | |
return this.x * cellSize + cellSize / 2; | |
} | |
yPx(cellSize: number): number { | |
return this.y * cellSize + cellSize / 2; | |
} | |
accept(visitor: CombineVisitor): void { | |
visitor.visit(this); | |
} | |
} | |
class PuyoPair { | |
constructor(private field: Field, public inPuyo: Puyo, public outPuyo: Puyo) { | |
} | |
draw(context, cellSize) { | |
/* | |
if (this.inPuyo.color === this.outPuyo.color) { | |
context.beginPath(); | |
context.lineWidth = 5; | |
context.strokeStyle=this.inPuyo.color; | |
context.moveTo(this.inPuyo.xPx(cellSize), this.inPuyo.yPx(cellSize)); | |
context.lineTo(this.outPuyo.xPx(cellSize), this.outPuyo.yPx(cellSize)); | |
context.stroke(); | |
} | |
*/ | |
this.inPuyo.draw(context, cellSize); | |
this.outPuyo.draw(context, cellSize); | |
} | |
//TODO hitting with fixed puyos | |
rotateRight(): PuyoPair { | |
if (this.inPuyo.x === this.outPuyo.x) { | |
if (this.inPuyo.y > this.outPuyo.y) { | |
this.outPuyo.x += 1; | |
this.outPuyo.y += 1; | |
if (this.outPuyo.x >= this.field.maxX) { | |
this.left(); | |
} | |
if (this.outPuyo.y >= this.field.maxY) { | |
this.up(); | |
} | |
} else { | |
this.outPuyo.x -= 1; | |
this.outPuyo.y -= 1; | |
if (this.outPuyo.x < 0) { | |
this.right(); | |
} | |
} | |
} else if (this.inPuyo.y === this.outPuyo.y) { | |
if (this.inPuyo.x > this.outPuyo.x) { | |
this.outPuyo.x += 1; | |
this.outPuyo.y -= 1; | |
if (this.outPuyo.x >= this.field.maxX) { | |
this.left(); | |
} | |
} else { | |
this.outPuyo.x -= 1; | |
this.outPuyo.y += 1; | |
if (this.outPuyo.x < 0) { | |
this.right(); | |
} | |
if (this.outPuyo.y >= this.field.maxY) { | |
this.up(); | |
} | |
} | |
} | |
return this; | |
} | |
/* | |
rotateLeft(): void { | |
if (this.inPuyo.x === this.outPuyo.x) { | |
if (this.inPuyo.y > this.outPuyo.y) { | |
this.outPuyo.x -= 1; | |
this.outPuyo.y += 1; | |
} else { | |
this.outPuyo.x += 1; | |
this.outPuyo.y -= 1; | |
} | |
} else if (this.inPuyo.y === this.outPuyo.y) { | |
if (this.inPuyo.x > this.outPuyo.x) { | |
this.outPuyo.x += 1; | |
this.outPuyo.y += 1; | |
} else { | |
this.outPuyo.x -= 1; | |
this.outPuyo.y -= 1; | |
} | |
} | |
} | |
*/ | |
right(): PuyoPair { | |
var maxX = Math.max(this.inPuyo.x, this.outPuyo.x); | |
if (maxX < this.field.maxX - 1 | |
&& !this.field.fixedPuyo(maxX + 1, this.inPuyo.y) && !this.field.fixedPuyo(maxX + 1, this.outPuyo.y)) { | |
this.inPuyo.x += 1; | |
this.outPuyo.x += 1; | |
} | |
return this; | |
} | |
left(): PuyoPair { | |
var minX = Math.min(this.inPuyo.x, this.outPuyo.x); | |
if (minX > 0 && !this.field.fixedPuyo(minX - 1, this.inPuyo.y) && !this.field.fixedPuyo(minX - 1, this.outPuyo.y)) { | |
this.inPuyo.x -= 1; | |
this.outPuyo.x -= 1; | |
} | |
return this; | |
} | |
down(): PuyoPair { | |
var maxY = Math.max(this.inPuyo.y, this.outPuyo.y); | |
if (maxY < this.field.maxY - 1 | |
&& !this.field.fixedPuyo(this.inPuyo.x, maxY + 1) && !this.field.fixedPuyo(this.outPuyo.x, maxY + 1)) { | |
this.inPuyo.y += 1; | |
this.outPuyo.y += 1; | |
} | |
return this; | |
} | |
up(): PuyoPair { | |
if (Math.min(this.inPuyo.y, this.outPuyo.y) > 0) { | |
this.inPuyo.y -= 1; | |
this.outPuyo.y -= 1; | |
} | |
return this; | |
} | |
} | |
var canvas1 = <HTMLCanvasElement>document.getElementById('canvas1'); | |
var canvas2 = <HTMLCanvasElement>document.getElementById('canvas2'); | |
var field1, field2; | |
function play(number) { | |
if (field1) { | |
field1.clear(); | |
} | |
if (field2) { | |
field2.clear(); | |
} | |
field1 = new AlphabetField(canvas1); | |
field1.init().start(); | |
if (number > 1) { | |
field2 = new ArrowField(canvas2); | |
field1.oppositeField = field2; | |
field2.oppositeField = field1; | |
field2.init().start(); | |
} | |
} | |
document.getElementById('start').onclick = function () { | |
if (field1) field1.start(); | |
if (field2) field2.start(); | |
} | |
document.getElementById('stop').onclick = function () { | |
if (field1) field1.stop(); | |
if (field2) field2.stop(); | |
} | |
document.getElementById('restart').onclick = function () { | |
if (field1) field1.init().start(); | |
if (field2) field2.init().start(); | |
} | |
document.getElementById('oneplay').onclick = function () { | |
play(1); | |
} | |
document.getElementById('twoplay').onclick = function () { | |
play(2); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment