Created
February 19, 2013 16:53
-
-
Save takatama/4987676 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
フルスクリーンにして遊んでください。 | |
(スペースを押すと画面がスクロールしてしまうので) | |
<登場人物> | |
○自分 | |
●敵 | |
■爆弾 | |
□炎 | |
<ルール> | |
自分が爆弾を置く。爆弾は炎となり、敵をやっつける。 | |
全ての敵をやっつけたらクリア。 | |
自分が敵か炎に触れるとゲームオーバー。 | |
<操作方法> | |
・矢印キーで移動 | |
・スペースキーで爆弾を置く | |
<開発メモ> | |
・interface にアクセス修飾子は定義できない |
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
<canvas id="stage" width="400" height="400"></canvas> | |
<br> | |
<input type="button" value="start" id="start"> | |
<input type="button" value="stop" id="stop"> |
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
class Entity { | |
static size: number = 40; | |
} | |
interface StaticEntity { | |
draw(context: CanvasRenderingContext2D): void; | |
isEnterable(): bool; | |
} | |
class Wall implements StaticEntity { | |
constructor(private x: number, private y: number) {} | |
draw(context: CanvasRenderingContext2D): void { | |
context.fillRect(this.x * Entity.size, this.y * Entity.size, Entity.size, Entity.size); | |
} | |
isEnterable(): bool { | |
return false; | |
} | |
} | |
class Space implements StaticEntity { | |
constructor(private x: number, private y: number) {} | |
draw(context: CanvasRenderingContext2D): void { | |
context.strokeRect(this.x * Entity.size, this.y * Entity.size, Entity.size, Entity.size); | |
} | |
isEnterable(): bool { | |
return true; | |
} | |
} | |
class MovingEntity { | |
constructor(public x: number, public y: number, private stage: Stage) {} | |
dropBomb(): void { | |
this.stage.addBomb(new Bomb(this.x, this.y, 20, this.stage)); | |
} | |
up(): void { | |
this.y = this.getNewY(-1); | |
} | |
right(): void { | |
this.x = this.getNewX(+1); | |
} | |
down(): void { | |
this.y = this.getNewY(+1); | |
} | |
left(): void { | |
this.x = this.getNewX(-1); | |
} | |
getNewY(dy: number): number { | |
if (this.stage.isEnterable(this.x, this.y + dy)) { | |
return this.y + dy; | |
} | |
return this.y; | |
} | |
getNewX(dx: number): number { | |
if (this.stage.isEnterable(this.x + dx, this.y)) { | |
return this.x + dx; | |
} | |
return this.x; | |
} | |
} | |
class Player extends MovingEntity { | |
draw(context: CanvasRenderingContext2D): void { | |
var x = this.x * Entity.size + Entity.size / 2, | |
y = this.y * Entity.size + Entity.size / 2, | |
radius = Entity.size / 3; | |
context.beginPath(); | |
context.arc(x, y, radius, 0, Math.PI*2, false); | |
context.stroke(); | |
} | |
} | |
class Enemy extends MovingEntity { | |
draw(context: CanvasRenderingContext2D): void { | |
var x = this.x * Entity.size + Entity.size / 2, | |
y = this.y * Entity.size + Entity.size / 2, | |
radius = Entity.size / 3; | |
context.beginPath(); | |
context.arc(x, y, radius, 0, Math.PI*2, false); | |
context.fill(); | |
} | |
} | |
class Bomb { | |
constructor(public x: number, public y: number, private count: number, private stage: Stage) {} | |
draw(context: CanvasRenderingContext2D): void { | |
var size = Entity.size / 3, | |
x = this.x * Entity.size + (Entity.size - size) / 2, | |
y = this.y * Entity.size + (Entity.size - size) / 2; | |
context.fillRect(x, y, size, size); | |
} | |
countDown(): void { | |
if (--this.count <= 0) { | |
this.stage.removeBomb(this); | |
this.fire(); | |
} | |
} | |
fire(): void { | |
this.addFire(this.x, this.y, 10); | |
this.addFire(this.x, this.y - 1, 10); | |
this.addFire(this.x + 1, this.y, 10); | |
this.addFire(this.x, this.y + 1, 10); | |
this.addFire(this.x - 1, this.y, 10); | |
} | |
addFire(x: number, y: number, count: number): void { | |
if (!this.stage.isEnterable(x, y)) { | |
return; | |
} | |
this.stage.addFire(new Fire(x, y, count, this.stage)); | |
} | |
} | |
class Fire { | |
size: number = 40; | |
constructor(public x: number, public y: number, private count: number, private stage: Stage) {} | |
draw(context: CanvasRenderingContext2D): void { | |
var size = this.size / 3, | |
x = this.x * this.size + (this.size - size) / 2, | |
y = this.y * this.size + (this.size - size) / 2; | |
context.strokeRect(x, y, size, size); | |
} | |
countDown(): void { | |
if (--this.count <= 0) { | |
this.stage.removeFire(this); | |
} | |
} | |
} | |
class Stage { | |
private context: CanvasRenderingContext2D; | |
private width: number; | |
private height: number; | |
private entities = []; //: StaticEntity[]; | |
private player: Player; | |
private enemies = []; //: Enemy[]; | |
private bombs = []; //: Bomb[]; | |
private fires = []; //: Fire[]; | |
private timer; | |
constructor(private canvas: HTMLCanvasElement, private map: string[]) { | |
this.context = canvas.getContext('2d'); | |
this.width = canvas.width; | |
this.height = canvas.height; | |
this.create(map); | |
} | |
private create(map: string[]) { | |
var i, len; | |
for (i = 0, len = map.length; i < len; i++) { | |
var row = map[i].split(','), | |
j, row_length; | |
for (j = 0, row_length = row.length; j < row_length; j++) { | |
switch (row[j]) { | |
case 'w': | |
this.addStaticEntity(new Wall(j, i)); | |
break; | |
case 's': | |
this.addStaticEntity(new Space(j, i)); | |
break; | |
case 'r': | |
this.addStaticEntity(new Space(j, i)).addPlayer(new Player(j, i, this)); | |
break; | |
case 'e': | |
this.addStaticEntity(new Space(j, i)).addEnemy(new Enemy(j, i, this)); | |
break; | |
} | |
} | |
} | |
new KeyController(this.getPlayer()); | |
} | |
public addStaticEntity(entity: StaticEntity): Stage { | |
this.entities.push(entity); | |
return this; | |
} | |
public addPlayer(player: Player): Stage { | |
this.player = player; | |
return this; | |
} | |
public addEnemy(enemy: Enemy): Stage { | |
this.enemies.push(enemy); | |
return this; | |
} | |
public addBomb(bomb: Bomb): Stage { | |
this.bombs.push(bomb); | |
return this; | |
} | |
public addFire(fire: Fire): Stage { | |
this.fires.push(fire); | |
return this; | |
} | |
public removeEnemy(enemy: Enemy): Stage { | |
return this.remove(this.enemies, enemy); | |
} | |
private remove(arr, object): Stage { | |
var i, len; | |
for (i = 0, len = arr.length; i < len; i++) { | |
if (arr[i] === object) { | |
arr.splice(i, 1); | |
return this; | |
} | |
} | |
return this; | |
} | |
public removeBomb(bomb: Bomb): Stage { | |
return this.remove(this.bombs, bomb); | |
} | |
public removeFire(fire: Fire): Stage { | |
return this.remove(this.fires, fire); | |
} | |
public drawAll(): void { | |
this.context.clearRect(0, 0, this.width, this.height); | |
this.draw(this.entities, this.context); | |
this.draw(this.enemies, this.context); | |
if (this.player) { | |
this.player.draw(this.context); | |
} | |
this.draw(this.bombs, this.context); | |
this.draw(this.fires, this.context); | |
} | |
private draw(arr, context) { | |
var i, len; | |
for (i = 0, len = arr.length; i < len; i++) { | |
if (arr[i]) { | |
arr[i].draw(context); | |
} | |
} | |
} | |
public getPlayer(): Player { | |
return this.player; | |
} | |
public isEnterable(x: number, y: number): bool { | |
var entity = this.getStaticEntity(x, y); | |
if (entity) { | |
return entity.isEnterable(); | |
} | |
return false; | |
} | |
private getStaticEntity(x: number, y: number): StaticEntity { | |
var i, len; | |
for (i = 0, len = this.entities.length; i < len; i++) { | |
if (this.entities[i].x === x && this.entities[i].y === y) { | |
return this.entities[i]; | |
} | |
} | |
return null; | |
} | |
//TODO refactor logic | |
public hitting(): void { | |
if (!this.player) { | |
return; | |
} | |
var i, len; | |
for (i = 0, len = this.fires.length; i < len; i++) { | |
if (!this.fires[i]) { | |
continue; | |
} | |
if (this.player.x === this.fires[i].x && this.player.y === this.fires[i].y) { | |
alert('game over'); | |
this.reset(); | |
} | |
var j, bombs_length; | |
for (j = 0, bombs_length = this.bombs.length; j < bombs_length; j++) { | |
if (!this.bombs[j]) { | |
continue; | |
} | |
if (this.fires[i].x === this.bombs[j].x && this.fires[i].y === this.bombs[j].y) { | |
this.bombs[j].fire(); | |
} | |
} | |
} | |
for (i = 0, len = this.enemies.length; i < len; i++) { | |
if (!this.enemies[i]) { | |
continue; | |
} | |
if (this.player.x === this.enemies[i].x && this.player.y === this.enemies[i].y) { | |
alert('game over'); | |
this.reset(); | |
} | |
var j, fire_length; | |
for (j = 0, fire_length = this.fires.length; j < fire_length; j++) { | |
if (!this.fires[j]) { | |
continue; | |
} | |
if (this.enemies[i].x === this.fires[j].x && this.enemies[i].y === this.fires[j].y) { | |
this.removeEnemy(this.enemies[i]); | |
if (this.enemies.length === 0) { | |
alert('clear'); | |
this.reset(); | |
} | |
} | |
} | |
} | |
} | |
public moveEnemies(): void { | |
var i, len; | |
for (i = 0, len = this.enemies.length; i < len; i++) { | |
switch (Math.floor(Math.random() * 50)) { | |
case 0: | |
break; | |
case 1: | |
this.enemies[i].up(); | |
break; | |
case 2: | |
this.enemies[i].right(); | |
break; | |
case 3: | |
this.enemies[i].down(); | |
break; | |
case 4: | |
this.enemies[i].left(); | |
break; | |
} | |
} | |
} | |
public countDownBombs(): void { | |
this.countDown(this.bombs); | |
this.countDown(this.fires); | |
} | |
private countDown(arr): void { | |
var i, len; | |
for (i = 0, len = arr.length; i < len; i++) { | |
if (arr[i]) { | |
arr[i].countDown(); | |
} | |
} | |
} | |
public stop() { | |
if(this.timer) { | |
clearInterval(this.timer); | |
} | |
} | |
public restart() { | |
var that = this; | |
this.timer = setInterval(function () { | |
that.countDownBombs(); | |
that.moveEnemies(); | |
that.drawAll(); | |
that.hitting(); | |
}, 100); | |
} | |
public reset(): void { | |
this.entities = []; | |
this.enemies = []; | |
this.bombs = []; | |
this.fires = []; | |
this.player = null; | |
if (this.map) { | |
this.create(this.map); | |
} | |
} | |
} | |
class KeyController { | |
constructor(private player: Player) { | |
var space = 32, left = 37, up = 38, right = 39, down = 40; | |
document.onkeydown = function (event) { | |
var chCode = (event.keyCode) ? event.keyCode : event.charCode; | |
switch(chCode) { | |
case space: | |
player.dropBomb(); | |
break; | |
case left: | |
player.left(); | |
break; | |
case right: | |
player.right(); | |
break; | |
case up: | |
player.up(); | |
break; | |
case down: | |
player.down(); | |
break; | |
} | |
} | |
} | |
} | |
// Main | |
var map = [ | |
"w,w,w,w,w,w,w", | |
"w,s,s,s,s,s,w", | |
"w,e,s,e,s,s,w", | |
"w,s,s,w,s,s,w", | |
"w,s,r,s,s,s,w", | |
"w,s,s,s,s,s,w", | |
"w,w,w,w,w,w,w" | |
]; | |
var stage: Stage = new Stage(<HTMLCanvasElement>document.getElementById('stage'), map); | |
stage.restart(); | |
document.getElementById('stop').onclick = function () { | |
stage.stop(); | |
} | |
document.getElementById('start').onclick = function () { | |
stage.restart(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment