ゲームエンジンを作ってます!
この素晴らしい冒険の紹介
ここ数週間、私は定期的に、キャンバスに基づいた JavaScript と HTML5 によるビデオ ゲーム エンジンの作成という、話したら面白いかもしれないと思うプロジェクトに取り組んできました。
おそらく、ビデオ ゲームを作成するために HTML5 と JavaScript を選択した理由を疑問に思っているのではないでしょうか?答えは質問ほどクールではありません。私の学校 (Zone01 Normandie) に必要なプロジェクトの競争であり、言語にはこのプロジェクトを実行するために必要なものがすべて揃っているという事実が、私がこれらのテクノロジーを選択した理由です。
しかし、実際には、これらは私がベースとして選択する言語ではなく、この言語が完成した後は、別の言語でこの種の別の冒険に乗り出すことになるでしょう。
建築
そこで、ビデオ ゲーム エンジンの設計に取り掛かりました。このエンジンは、少なくとも 2 つの主要なクラスを含むいくつかのクラスで構成されます。ゲーム領域全体を管理する Game クラスと、オブジェクトを生成できる GameObject クラスです。私たちのゲームで相互に対話できるようにします。
これらのクラスに、すべてのオブジェクトのコリジョン ボックスを管理できるようにする CollideBox クラスを追加します。
Game クラスには、ゲームの各フレーム (画像) で実行される GameLoop メソッドと、各ゲーム ループ中に呼び出される Draw メソッドがあります。
GameObjectクラスにはStepメソッドとDrawメソッドがあります。
1 つ目はゲーム ループの各ラウンドを実行し、2 つ目は GameLoop クラスの Draw メソッドが呼び出されるたびに実行します。
これにより、エンジン モジュールをプロジェクトにインポートすることで、理論的にはゲームを作成できるようになります。
スプライトを表示するために、HTML5 に組み込まれている canva API を使用することにしました (組み込みとは、デフォルトで付属していることを意味します)
これにより、すべてのスプライトを表示し、画像を再カットしてアニメーションを作成できるようになり、非常に便利になります!
数日後、アニメーションを一定の速度で表示できるようになり、CollideBox 経由で衝突を検出できるようになりました。
他にもたくさんの素晴らしいものを以下に紹介します:
ゲームオブジェクト クラス
クラスゲームオブジェクト{
constructor(game) { // ゲームオブジェクトを初期化します
this.x = 0
this.y = 0
this.sprite_img = {ファイル:未定義、列:1、行:1、fw:1、fh:1、ステップ:0、anim_speed:0、スケール:1}
this.loaded = false
this.game = ゲーム
this.kill = false
this.collision = 新しい CollideBox()
game.gObjects.push(this)
};
setSprite(img_path, row=1,col=1,speed=12,scale=1) {
var img = 新しい画像();
img.onload = () => {
console.log("イメージが読み込まれました")
this.sprite_img = {file:img、col:col、row:row、fw:img.width/col、fh:img.height/row、step:0、anim_speed:speed、scale:scale}
this.onSpriteLoaded()
};
img.src = img_path
}
onSpriteLoaded() {}
draw(context, Frame) { // ゲームオブジェクトの描画関数
if (this.sprite_img.file != 未定義) {
let 列 = this.sprite_img.step % this.sprite_img.col;
let row = Math.floor(this.sprite_img.step / this.sprite_img.col);
// context.clearRect(this.x, this.y, this.sprite_img.fw, this.sprite_img.fh);
context.drawImage(
この.sprite_img.ファイル、
this.sprite_img.fw * 列、
this.sprite_img.fh * 行、
this.sprite_img.fw、
this.sprite_img.fh、
この.x、
これ、y、
this.sprite_img.fw * this.sprite_img.scale,
this.sprite_img.fh * this.sprite_img.scale
);
if (フレーム % Math.floor(60 / this.sprite_img.anim_speed) === 0) {
// 12 fps でのみステップ更新
if (this.sprite_img.step box.x &&
this.collision.y box.y
)
}
onStep() {};
}
class GameObject{
constructor(game) { // Initialize the GameObject
this.x = 0
this.y = 0
this.sprite_img = {file: undefined, col: 1, row: 1, fw: 1, fh: 1, step: 0, anim_speed: 0, scale: 1}
this.loaded = false
this.game = game
this.kill = false
this.collision = new CollideBox()
game.gObjects.push(this)
};
setSprite(img_path, row=1, col=1, speed=12, scale=1) {
var img = new Image();
img.onload = () => {
console.log("image loaded")
this.sprite_img = {file: img, col: col, row: row, fw: img.width / col, fh: img.height / row, step: 0, anim_speed: speed, scale: scale}
this.onSpriteLoaded()
};
img.src = img_path
}
onSpriteLoaded() {}
draw(context, frame) { // Draw function of game object
if (this.sprite_img.file != undefined) {
let column = this.sprite_img.step % this.sprite_img.col;
let row = Math.floor(this.sprite_img.step / this.sprite_img.col);
// context.clearRect(this.x, this.y, this.sprite_img.fw, this.sprite_img.fh);
context.drawImage(
this.sprite_img.file,
this.sprite_img.fw * column,
this.sprite_img.fh * row,
this.sprite_img.fw,
this.sprite_img.fh,
this.x,
this.y,
this.sprite_img.fw * this.sprite_img.scale,
this.sprite_img.fh * this.sprite_img.scale
);
if (frame % Math.floor(60 / this.sprite_img.anim_speed) === 0) {
// Mise à jour de step seulement à 12 fps
if (this.sprite_img.step box.x &&
this.collision.y box.y
)
}
onStep() {};
}
ゲーム クラス
クラス ゲーム {
コンストラクター(幅 = 1400、高さ = 700) {
this.gObjects = [];
this.toLoad = [];
this.timers = [];
this.layers = [];
this.canvas = document.getElementsByTagName("canvas")[0]
this.canvas.width = 幅
this.canvas.height = 高さ
this.context = this.canvas.getContext("2d")
this.context.globalCompositeOperation = 'ソースオーバー';
this.inputs = {};
this.mouse = {x:0,y:0}
document.addEventListener('keydown', (e) => {
this.inputs[e.key] = true;
}、 間違い);
document.addEventListener('keyup', (e) => {
this.inputs[e.key] = false;
}、 間違い);
document.addEventListener('mousemove', (e) => {
this.mouse.x = e.x;
this.mouse.y = e.y;
})
document.addEventListener('mouseevent', (e) => {
スイッチ (e.button) {
}
})
}
描画(フレーム) {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
console.log(this.canvas.width, this.canvas.height)
for(let i = 0; i {
時計 = 1
for(let i = 0; i class GameObject{
constructor(game) { // Initialize the GameObject
this.x = 0
this.y = 0
this.sprite_img = {file: undefined, col: 1, row: 1, fw: 1, fh: 1, step: 0, anim_speed: 0, scale: 1}
this.loaded = false
this.game = game
this.kill = false
this.collision = new CollideBox()
game.gObjects.push(this)
};
setSprite(img_path, row=1, col=1, speed=12, scale=1) {
var img = new Image();
img.onload = () => {
console.log("image loaded")
this.sprite_img = {file: img, col: col, row: row, fw: img.width / col, fh: img.height / row, step: 0, anim_speed: speed, scale: scale}
this.onSpriteLoaded()
};
img.src = img_path
}
onSpriteLoaded() {}
draw(context, frame) { // Draw function of game object
if (this.sprite_img.file != undefined) {
let column = this.sprite_img.step % this.sprite_img.col;
let row = Math.floor(this.sprite_img.step / this.sprite_img.col);
// context.clearRect(this.x, this.y, this.sprite_img.fw, this.sprite_img.fh);
context.drawImage(
this.sprite_img.file,
this.sprite_img.fw * column,
this.sprite_img.fh * row,
this.sprite_img.fw,
this.sprite_img.fh,
this.x,
this.y,
this.sprite_img.fw * this.sprite_img.scale,
this.sprite_img.fh * this.sprite_img.scale
);
if (frame % Math.floor(60 / this.sprite_img.anim_speed) === 0) {
// Mise à jour de step seulement à 12 fps
if (this.sprite_img.step box.x &&
this.collision.y box.y
)
}
onStep() {};
}
確かに最適化やその他のエラーがたくさんありますが、すべて機能しています。
"完璧!"教えてもらえますか?
それは単純すぎます。
心配事
これを完了し、このエンジンでゲームを作成するためのテストを開始した後、同僚との会話中に恐ろしいニュースを知りました。
テクノロジーの選択は、私の Zone01 学校の要件に対応するために行われたことを覚えていると思います…
確かに、選択された言語は良かったのですが、プロジェクトに重大な支障をきたすような指示があるとは知りませんでした…
Canva ライブラリの使用が禁止されました!
念のため言っておきますが、これは画像を表示するために使用するライブラリです。
次は何でしょうか?
このテキストを書きながら、canva を使用せずにこのゲーム エンジンを完全に再設計し始めています。
この開発ブログは終了しました。このストーリーの残りの部分はすぐにご覧いただけます。ご心配なく。
次回の開発ブログでは、必ず新しいフォーマットを試してみます。
このコンテンツがあなたを助け、楽しませ、少なくともいくつかの主題について教育したことを願っています。一日の終わりとコーディングがうまくいくことを祈っています。
DevLogs 1.1: エンジンは完成しましたが、どのように動作するのでしょうか?
以前
数か月前にビデオ ゲーム エンジンの作成を開始し、完成しました...かなり前に、Zone01 の数人の同僚の協力を得て、スーパー マリオ ブラザーズにインスピレーションを得たゲームを作成することにも成功しました。 itch.io ページ。
この開発ブログに適用する形式を決定するのに多くの時間がかかり、この開発ブログの執筆期限をわずかに遅らせたか、完全に遅らせたことは認めます。
このテーマに取り組めなかった自分の優柔不断の言い訳を辛抱強く受け入れ、今では発売予定日から 2 か月後、電車がキャンセルになったためにさらに 1 時間待たされる中、ルーアンのバス停の休憩所で原稿を書いている自分に気づきました。
それでは、アーキテクチャの詳細をすべて説明しましょう。このアーキテクチャは、私の開発ブログの最初の部分から (キャンバスの使用を避けることによる調整を除けば) ほとんど変更されていません。
そこで、実行されたプロジェクト、チームとしての取り組み方、遭遇した問題についてお話します。
これをこのプロジェクトへのフィードバックとして捉えてください。この記事からいくつかの教訓を引き出して、あなたのプロジェクトに役立てていただければ幸いです。
プロジェクト
このプロジェクトは、少なくともコードに関しては、JavaScript でスーパー マリオ ブラザーズを再作成することでした。
仕様はシンプルで、マリオ ゲームにいくつかのレベルがあり、新しいレベルを簡単に作成できる方法が必要でした。
また、オプションを調整するためにスコアボードとメニューを作成する必要がありました。
このプロジェクトの難しさは次のとおりです:
画面上の要素の水平スクロール-
画面上に存在しない要素の最適化-
すべての要素がプレーヤーの位置を基準にしてバックグラウンドでスクロールする必要があるため、スクロールします。
また、画面に表示されない要素を最適化すると、パフォーマンスを低下させることなくゲームを実行するために必要なリソースが削減されます。
これらの問題を解決した後、このゲームを私の itch.io ページに公開し、実際にテストすることもできます。
この開発ブログはこれで終わります。これで、他のプロジェクトや他の主題について書くことができるようになります。
私の話に少しでも興味があれば、github で私のさまざまなプロジェクト (この開発ブログのプロジェクトを含む) をご覧ください。
今日も素敵な一日をお過ごしください!