0
0

More than 5 years have passed since last update.

# EgretEngineで超簡単なゲームを作ってみよう(4) 障害物の実装と各種カプセル化

Last updated at Posted at 2018-10-26

# 簡単な解説

EgretEngineで超簡単なゲームを作ってみよう(3) 自然落下するボールとタップで上へ力をあたえるの例と違って複数のオブジェクトがでてきますので、GameObject(およびPhysicsObject)クラスを作成しまして、そこで物理エンジンとEgretの描画オブジェクトの管理を行っています

# ソースコード全体

``````const BASKET_SIZE_METER = 0.15;
const BALL_SIZE_METER = 0.6;

class Main extends egret.DisplayObjectContainer {
public constructor() {
super();
}

const ballPixel = egret.MainContext.instance.stage.stageWidth / 10;
GameWorld.init(ballPixel / BALL_SIZE_METER,this.stage);
new Sky();
new Ground();
const  ball = new Ball();
this.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, (e: egret.TouchEvent) => ball.up(), this);
GameWorld.start((dt) => {
const gn = Math.random();
if (2000 < lastBasketCreation && gn < 0.05) {
}
});
}
}

function random(min:number, max:number) {
return min + Math.random() * (max -min);
}

class GameWorld {
public static world: p2.World;
private static pixelPerMeter: number;
private static meterPerPixel: number;
public static objects: GameObject[] = [];
public static stageHeight: number;
public static stageWidth: number;
public static stageHeightMeter: number;
public static stageWidthMeter: number;
public static displayObjectContainer: egret.DisplayObjectContainer;

static pixelToMeter(pixel: number) : number {
return pixel / this.pixelPerMeter;
}
static meterToPixel(meter: number) : number {
return meter * this.pixelPerMeter;
}
static xMeterToPixel(meter: number) : number{
return this.meterToPixel(meter);

}
static yMeterToPixel(meter: number) : number {
return this.stageHeight - this.meterToPixel(meter);
}

static init(pixelPerMeter: number, displayObjectContainer: egret.DisplayObjectContainer) {
this.pixelPerMeter = pixelPerMeter;
this.meterPerPixel =  1 / pixelPerMeter;

this.stageHeight = egret.MainContext.instance.stage.stageHeight;
this.stageWidth = egret.MainContext.instance.stage.stageWidth;
this.stageHeightMeter  = this.pixelToMeter(this.stageHeight);
this.stageWidthMeter = this.pixelToMeter(this.stageWidth);

this.displayObjectContainer = displayObjectContainer;

const world = new p2.World();
world.sleepMode = p2.World.BODY_SLEEPING;
world.gravity = [0, -9.8];
this.world = world;
}

static start(globalProcess:(deltaTime:number) => void) {
const loop = (deltaTime: number) => {
if (deltaTime < 10) {
return;
}
if (deltaTime > 1000) {
return;
}

this.world.step(1/60, deltaTime / 1000, 10);
const l = this.objects.length;
for (let i: number = 0; i < l; i++) {
const o = this.objects[i];
if (!o.inited && !o.toDelete) {
o.init();
}
}

let someoneIsDeleted = false;
for (let i: number = 0; i < l; i++) {
const o = this.objects[i];
if (o.inited && !o.toDelete) {
o.process();
}
}
if (globalProcess) {
globalProcess(deltaTime);
}
for (let i: number = 0; i < l; i++) {
const o = this.objects[i];
if (o.toDelete) {
someoneIsDeleted = true;
continue;
}
if (o.inited) {
o.update();
}
}
if (!someoneIsDeleted) {
return;
}
this.objects = this.objects.filter((i) => {
if (!i.toDelete) {
return true;
}
i.delete();
return false;
});
};
egret.Ticker.getInstance().register(loop, this.displayObjectContainer);
}
}

abstract class GameObject {
protected display: egret.DisplayObject;
toDelete:boolean = false;
inited:boolean = false;

constructor() {
GameWorld.objects.push(this);
}

init() {
this.display = this.createDisplay();
this.inited = true;
}

abstract createDisplay() : egret.DisplayObject;
abstract process() : void;

update() {}

markToDelete() {
this.toDelete = true;
}

delete() {
GameWorld.displayObjectContainer.removeChild(this.display);
}
}

abstract class PhysicsObject extends GameObject {
protected body: p2.Body;

constructor() {
super();
}

init() {
super.init();
this.body = new p2.Body(this.options());
this.body.displays = [this.display];
}

abstract options() : any;

const shape = this.createShape();
}

createShape() : p2.Shape {
throw new Error("createShape or addShapeToBody must be implemented");
}

update() {
const body = this.body;
const display: egret.DisplayObject = this.display;
if (!display) {
return;
}
display.x = GameWorld.xMeterToPixel(body.position[0]);
display.y = GameWorld.yMeterToPixel(body.position[1]);
display.rotation = 360 - (body.angle + body.shapes[0].angle) * 180 / Math.PI;
}

delete() {
super.delete();
GameWorld.world.removeBody(this.body);
this.body.displays = [];
this.body = null;
}
}

class Sky extends GameObject {
options() {
return {type: p2.Body.KINEMATIC};
}

createDisplay() {
const sprite = new egret.Sprite();
const g = sprite.graphics;
g.clear();
g.beginFill(0x8080ff,1);
g.drawRect(0,0, GameWorld.stageWidth, GameWorld.stageHeight);

g.endFill();
g.beginFill(0xc0c0ff);
g.drawCircle(0, 0, GameWorld.stageWidth);
return  sprite;
}

process() {}
}

class Ball extends PhysicsObject {
private bx: number;
private toUp: number = 0;

constructor() {
super();
this.bx = GameWorld.stageWidthMeter / 4;
}

options() {
return { mass: 1, force:[0,-300], position: [this.bx, GameWorld.stageHeightMeter / 2] };
}

up() {
this.toUp++;
}

process() {
this.body.position[0] = this.bx;
this.body.angle = 0;
if (this.toUp) {
this.body.applyForceLocal([0, 500 * this.toUp],[0,0]);
this.toUp = 0;
}
}

createShape() : p2.Shape {
return new p2.Circle({ radius: BALL_SIZE_METER / 2 });
}

createDisplay(): egret.DisplayObject {
const shape = new egret.Shape();
shape.graphics.beginFill(0xff0000);
shape.graphics.drawCircle(0, 0, GameWorld.meterToPixel(BALL_SIZE_METER / 2 ));
shape.graphics.endFill();
return shape;
}
}

class Ground extends PhysicsObject {
options() {
return {position:[0, 1],type: p2.Body.STATIC};
}

createShape() : p2.Shape {
return new p2.Plane({angle: Math.PI});
}

createDisplay(): egret.DisplayObject {
const shape = new egret.Shape();
shape.graphics.beginFill(0x400000);
shape.graphics.drawRect(0,0, GameWorld.stageWidth, GameWorld.meterToPixel(1));
shape.graphics.endFill();
return shape;
}

process() {
}
}

private lengthMeter: number;
private halfLengthMeter: number;
private velocityX: number;

constructor() {
super();
this.lengthMeter = BALL_SIZE_METER + BASKET_SIZE_METER + random(0.1,0.5);
this.halfLengthMeter = this.lengthMeter / 2;
this.velocityX = random(-2.5,-1);
}

options() {
return {gravityScale:0, mass: 40, position: [10, random(2,7)], velocity:[this.velocityX ,0] };
}

createDisplay() : egret.Shape  {
const lx  = GameWorld.xMeterToPixel((0 - this.halfLengthMeter));
const rx  = GameWorld.xMeterToPixel((0 + this.halfLengthMeter));

const shape = new egret.Shape();
const g = shape.graphics;
g.beginFill(0xffff00, 1);

g.lineStyle(5, 0xfff000,0.5);
g.moveTo(lx, 0);
g.lineTo(rx, 0);

g.endFill();

return shape;
}

}

process() {
if (this.body && this.body.position[0] < -1) {
this.markToDelete();
}
}

}

``````
0
0
0

Register as a new user and use Qiita more conveniently

1. You get articles that match your needs
2. You can efficiently read back useful information
3. You can use dark theme
What you can do with signing up
0
0