Skip to content

Instantly share code, notes, and snippets.

@takatama
Created February 19, 2013 16:51
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/4987660 to your computer and use it in GitHub Desktop.
Save takatama/4987660 to your computer and use it in GitHub Desktop.
TypeScript入門 シューティングゲーム編
TypeScriptを使ってシューティングゲームを作ってみた。
敵に当たるとゲームオーバー。
<操作方法>
・左右キーで移動。スペースキーで発射。
<開発メモ>
・当たり判定にVisitorパターンを使っている。
body { background-color: #DDDDDD; font: 30px sans-serif; }
<canvas id="stage" width="400" height="400"></canvas>
<br>
<input type="button" id="stop" value="stop">
<input type="button" id="restart" value="restart">
// forked from takatama's "2013-02-04 1st" http://jsdo.it/takatama/uoPT
interface Entity {
x: number;
y: number;
radius: number;
isHit(entity: Entity): bool;
draw(context: CanvasRenderingContext2D): void;
move(): void;
destroy(): void;
accept(visitor: Visitor): void;
}
class BaseEntity implements Entity {
constructor(public stage: Stage, public x: number, public y: number, public radius: number, public dx: number, public dy: number) {
}
isHit(entity: Entity): bool {
var distance = Math.sqrt(Math.pow((this.x - entity.x), 2) + Math.pow((this.y - entity.y), 2));
return (distance < this.radius + entity.radius);
}
draw(context): void {
context.beginPath();
context.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
context.stroke();
}
move(): void {
this.x += this.dx;
if (this.x < 0) {
this.x = this.stage.getWidth();
} else if (this.x > this.stage.getWidth()) {
this.x = 0;
}
this.y += this.dy;
if (this. y < 0) {
this.y = this.stage.getHeight();
} else if (this.y > this.stage.getHeight()) {
this.y = 0;
}
}
destroy(): void {}
accept(visitor: Visitor): void {}
}
class MyBall extends BaseEntity {
move(): void {
this.x += this.dx;
if (this.x < 0) {
this.x = this.stage.getWidth();
} else if (this.x > this.stage.getWidth()) {
this.x = 0;
}
this.y += this.dy;
if (this. y < 0 || this.y > this.stage.getHeight()) {
this.stage.removeMyBall(this);
}
}
destroy(): void {
this.stage.removeMyBall(this);
}
}
class MyFighter extends BaseEntity {
destroy(): void {
this.stage.removeMyFighter(this);
}
fire(): void {
this.stage.addMyBall(new MyBall(this.stage, this.x, this.y, 2, 0, -15));
}
turnLeft(): void {
this.dx = -10;
}
turnRight(): void {
this.dx = 10;
}
}
class EnemyFighter extends BaseEntity {
move(): void {
this.x += this.dx;
if (this.x < 0) {
this.x = this.stage.getWidth();
} else if (this.x > this.stage.getWidth()) {
this.x = 0;
}
this.y += this.dy;
if (this. y > this.stage.getHeight()) {
this.stage.removeEnemy(this);
}
}
destroy(): void {
this.stage.removeEnemy(this);
}
accept(visitor: Visitor): void {
visitor.visitEnemy(this);
}
}
interface Visitor {
visitEnemy(enemy: Entity): void;
}
class FighterVisitor implements Visitor {
constructor(private stage: Stage, private fighter: Entity) {
}
visitEnemy(enemy: Entity): void {
if (this.fighter) {
if (this.fighter.isHit(enemy)) {
alert('game over');
this.stage.restart();
}
}
}
}
class BallVisitor implements Visitor {
constructor(private stage: Stage, private ball: Entity) {
}
visitEnemy(enemy: Entity): void {
if (this.ball.isHit(enemy)) {
enemy.destroy();
}
}
}
class KeyController {
constructor(private fighter: MyFighter) {
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:
fighter.fire();
break;
case left:
fighter.turnLeft();
break;
case right:
fighter.turnRight();
break;
}
}
}
}
class Stage {
private myFighter: Entity;
private myBalls: Entity[] = [];
private enemies: Entity[] = [];
private context: CanvasRenderingContext2D;
private width: number;
private height: number;
private time: number = 0;
private timer: number;
constructor(private canvas: HTMLCanvasElement) {
this.context = canvas.getContext('2d');
this.width = canvas.width;
this.height = canvas.height;
}
restart(): void {
this.stop();
this.myBalls = [];
this.enemies = [];
var that = this;
this.timer = setInterval(function () {
that.tick();
}, 100);
}
stop(): void {
if (this.timer) {
clearTimeout(this.timer);
}
}
tick(): void {
this.time++;
this.createEnemy();
this.moveAll();
this.hittingAll();
this.drawAll();
}
createEnemy(): void {
if (this.time % 10 === 0) {
this.addEnemy(new EnemyFighter(this, Stage.random(this.width), 0, 15, 0, 3));
}
}
static random(max: number): number {
return Math.floor(Math.random() * max);
}
moveAll(): void {
this.moveEntities(this.enemies);
this.moveEntities(this.myBalls);
if (this.myFighter) {
this.myFighter.move();
}
}
moveEntities(entities: Entity[]): void {
var i, len;
for (i = 0, len = entities.length; i < len; i++) {
if (entities[i]) {
entities[i].move();
}
}
}
hittingAll(): void {
this.processMyFighterHitting();
this.processMyBallsHitting();
}
processMyFighterHitting() {
this.visitEnemies(new FighterVisitor(this, this.myFighter));
}
visitEnemies(visitor: Visitor): void {
var i, len
for (i = 0, len = this.enemies.length; i < len; i++) {
if (this.enemies[i]) {
this.enemies[i].accept(visitor);
}
}
}
processMyBallsHitting() {
var i, len;
for (i = 0, len = this.myBalls.length; i < len; i++) {
if (this.myBalls[i]) {
this.visitEnemies(new BallVisitor(this, this.myBalls[i]));
}
}
}
drawAll(): void {
this.drawFrame();
this.drawEntities(this.enemies);
this.drawEntities(this.myBalls);
if (this.myFighter) {
this.myFighter.draw(this.context);
}
}
drawFrame(): void {
this.context.clearRect(0, 0, this.width, this.height);
this.context.strokeRect(0, 0, this.width, this.height);
}
drawEntities(entities: Entity[]): void {
var i, j, len = entities.length;
for (i = 0; i < len; i++) {
if (entities[i]) {
entities[i].draw(this.context);
}
}
}
setMyFighter(fighter: MyFighter): void {
this.myFighter = fighter;
new KeyController(fighter);
}
addEnemy(enemy: Entity): void {
this.add(this.enemies, enemy);
}
addMyBall(ball: MyBall): void {
this.add(this.myBalls, ball);
}
add(entities: Entity[], entity: Entity): void {
var i, len;
for (i = 0, len = entities.length; i < len; i++) {
if (entities[i] == null) {
entities[i] = entity;
return;
}
}
entities.push(entity);
}
removeMyFighter(fighter: Entity): void {
this.myFighter = null;
}
removeEnemy(enemy: Entity): void {
this.remove(this.enemies, enemy);
}
removeMyBall(ball: Entity): void {
this.remove(this.myBalls, ball);
}
remove(entities: Entity[], entity: Entity): void {
var i, len;
for (i = 0, len = entities.length; i < len; i++) {
if (entity === entities[i]) {
entities[i] = null;
return;
}
}
}
getWidth(): number {
return this.width;
}
getHeight(): number {
return this.height;
}
}
/* Main */
var stage: Stage = new Stage(<HTMLCanvasElement>document.getElementById('stage'));
stage.setMyFighter(new MyFighter(stage, 150, 380, 10, 10, 0));
document.getElementById('stop').onclick = function() {
stage.stop();
};
document.getElementById('restart').onclick = function() {
stage.restart();
};
stage.restart();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment