Skip to content

Instantly share code, notes, and snippets.

@takatama
Created February 19, 2013 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takatama/4987676 to your computer and use it in GitHub Desktop.
Save takatama/4987676 to your computer and use it in GitHub Desktop.
TypeScript入門 爆弾男編
フルスクリーンにして遊んでください。
(スペースを押すと画面がスクロールしてしまうので)
<登場人物>
○自分
●敵
■爆弾
□炎
<ルール>
自分が爆弾を置く。爆弾は炎となり、敵をやっつける。
全ての敵をやっつけたらクリア。
自分が敵か炎に触れるとゲームオーバー。
<操作方法>
・矢印キーで移動
・スペースキーで爆弾を置く
<開発メモ>
・interface にアクセス修飾子は定義できない
<canvas id="stage" width="400" height="400"></canvas>
<br>
<input type="button" value="start" id="start">
<input type="button" value="stop" id="stop">
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