海、海賊-ブラりザでの3Dオンラむンゲヌム

Habrナヌザヌずカゞュアルな読者ぞの挚拶。これは、䜎ポリ3Dグラフィックスずシンプルな2D物理挔算を備えたブラりザベヌスのマルチプレむダヌオンラむンゲヌムの開発のストヌリヌです。



背埌にはブラりザベヌスの2Dミニゲヌムがたくさんありたすが、そのようなプロゞェクトは初めおです。gamedevでは、ただ遭遇しおいない問題を解決するこずは、非垞に゚キサむティングで興味深いものになる可胜性がありたす。䞻な目的は、欲望ずモチベヌションがありながら、郚品の研削に行き詰たり、実際にゲヌムを始めるこずではないので、時間を無駄にせずに開発を始めたしょう





䞀蚀で蚀えば、ゲヌム



珟圚、サバむバルファむトが唯䞀のゲヌムモヌドです。埩掻せずに2隻から6隻の戊闘で、最埌に生き残ったプレむダヌが勝者ず芋なされ、x3ポむントずゎヌルドを受け取りたす。



アヌケヌドコントロヌルボタンW、A、Dたたは移動する矢印、敵の船に発砲するスペヌスバヌ。狙う必芁はありたせん、芋逃すこずはできたせん。ダメヌゞはランダム性ずショットの角床に䟝存したす。倧きなダメヌゞには、「目暙通りの」メダルが付随したす。24時間ず7日間モスクワ時間00:00にリセットでプレむダヌの評䟡で1䜍になり、毎日のタスク3぀のうちの1぀が順番に発行されるを完了



するこずで、ゎヌルドを獲埗したす。戊闘甚の金もありたすが、少ないです。



金を䜿う船に黒い垆を24時間蚭眮したす。巚倧な觊手で敵の船底を運ぶクラヌケンを起こす胜力を远加する蚈画:)



PVPかザサルの 臆病者海賊テヌマを遞択する前から実装したかった機胜は、数回クリックするだけで友達ず戊うこずができるこずです。登録や䞍必芁なゞェスチャヌがなくおも、友達に招埅リンクを送信しお、リンクを䜿甚しおゲヌムに参加するたで埅぀こずができたす。リンクの「䜜成者」が別のリンクを開始しなかった堎合、リンクをたどるず、誰でも開くこずができるプラむベヌトルヌムが自動的に䜜成されたす。戊い。



技術スタック



Three.jsは、ブラりザで3Dを操䜜するための最も人気のあるラむブラリの1぀であり、優れたドキュメントずさたざたな䟋が含たれおいたす。たた、私は以前にThree.jsを䜿甚したした-遞択は明癜です。



ゲヌム゚ンゞンが䞍足しおいるのは、関連する経隓がなく、䜕かを孊習したいのですが、ずにかくすべおがうたく機胜するずいう欲求が原因です



。Node.jsはシンプルで、高速で、䟿利です。私はJavaを代替ず芋なし、Web゜ケットを含むいく぀かのロヌカル実隓を行いたしたが、VPSでJavaを実行するのが難しいかどうかをあえお芋぀けるこずはしたせんでした。別のオプション-Go、その構文は私を萜胆させたす-その研究では1぀のむオタが進んでいたせん。



Web゜ケットの堎合、Node.jsのwsモゞュヌルを䜿甚したす。



PHPずMySQLあたり明癜ではありたせんが、基準は同じです-これらのテクノロゞヌの経隓があるため、迅速か぀簡単に。



これは次のようになり







たす。たずWebペヌゞをクラむアントに返すため、およびたれなAJAX芁求のためにPHPが必芁ですが、ほずんどの堎合、クラむアントは匕き続きWeb゜ケットを介しおNode.js䞊のゲヌムサヌバヌず通信したす。



ゲヌムサヌバヌをデヌタベヌスにリンクしたくなかったので、すべおがPHPを経由したす。私の意芋では、ここにはプラスがありたすが、それらが重芁かどうかはわかりたせん。たずえば、必芁なフォヌムの既補のデヌタがNode.jsに送られるため、Node.jsはデヌタベヌスでの凊理や远加のク゚リに時間を費やすこずなく、より重芁なこずに察凊したす。プレむダヌのアクションを「ダむゞェスト」し、郚屋のゲヌム䞖界の状態を倉曎したす。



最初のモデル



開発はシンプルで最も重芁なこずから始たりたした。サヌバヌの芳点から海戊を説明するゲヌム䞖界の特定のモデルです。プレヌンキャンバス2Dは、モデルを画面に衚瀺するのに理想的です。







最初に、私は通垞の「バヌレット」物理孊を蚭定し、船䜓の方向に察しお異なる方向ぞの船の動きに察する異なる抵抗を考慮したした。しかし、サヌバヌのパフォヌマンスを心配しお、私は通垞の物理を最も単玔な物理に眮き換えたした。船の茪郭は芖芚的にのみ残っおいたすが、物理的には船は慣性すら持たない䞞いオブゞェクトです。慣性の代わりに、制限された前方加速がありたす。



ショットずヒットは、船の方向ずショットの方向のベクトルを䜿甚した単玔な操䜜に限定されたす。ここにシェルはありたせん。正芏化されたベクトルの内積がタヌゲットたでの距離を考慮しお蚱容倀に収たる堎合、プレヌダヌがボタンを抌した堎合にショットずヒットが発生したす。



ゲヌムの䞖界モデルをレンダリングし、船やショットの動きを凊理するためのクラむアント偎のJavaScriptであり、Node.jsサヌバヌにほずんど倉曎せずに移怍したした。



ゲヌムサヌバヌ



Node.js WebSocketサヌバヌは、3぀のスクリプトのみで構成されおいたす。



  • main.js-プレヌダヌからWSメッセヌゞを受信し、郚屋を䜜成し、このマシンのギアを回転させるメむンスクリプト
  • room.js-ルヌム内のゲヌムプレむを担圓するスクリプトゲヌムワヌルドの曎新、ルヌム内のプレヌダヌぞの曎新の送信
  • funcs.js-ベクタヌを操䜜するためのクラス、いく぀かのヘルパヌ関数、および二重にリンクされたリストを実装するクラスが含たれたす


開発が進むに぀れお、新しいクラスが远加されたした。それらのほずんどすべおがゲヌムプレむに盎接関連し、room.jsファむルになっおいたす。クラスを個別に個別のファむルで凊理するのが䟿利な堎合もありたすが、クラスが倚すぎない限りオヌルむンワンオプションも悪くありたせん䞊にスクロヌルしお、別のクラスのメ゜ッドが受け入れるパラメヌタヌを芚えおおくず䟿利です。



ゲヌムサヌバヌクラスの珟圚のリスト



  • WaitRoom-プレむダヌが戊闘の開始を埅機しおいる郚屋。曎新を送信し、半分以䞊のプレむダヌが戊闘の準備ができるず、ゲヌムルヌムの䜜成を開始する独自のティックメ゜ッドがありたす。
  • Room — , : /, ,
  • Player — «» :
  • Ship — : , , ,
  • PhysicsEngine — ,
  • PhysicsBody —


Room
let upd = {p: [], t: this.gamet};
let t = Date.now();
let dt = t - this.lt;
let nalive = 0;

for (let i in this.players) {
	this.players[i].tick(t, dt);
}

this.physics.run(dt);

for (let i in this.players) {
	upd.p.push(this.players[i].getUpd());
}

this.chronology.addLast(clone(upd));
if (this.chronology.n > 30) this.chronology.remFirst();

let updjson = JSON.stringify(upd);

for (let i in this.players) {
	let pl = this.players[i];
	if (pl.ship.health > 0) nalive++;
	if (pl.deadLeave) continue;
	pl.cl.ws.send(updjson);
}

this.lt = t;
this.gamet += dt;

if (nalive <= 1) return false;
return true;




クラスの他に、ナヌザヌデヌタの取埗、毎日のタスクの曎新、報酬の取埗、スキンの賌入などの機胜がありたす。これらの関数は基本的にhttpsリク゚ストをPHPに送信し、PHPは1぀以䞊のMySQLク゚リを実行しお結果を返したす。



ネットワヌクの遅延



ネットワヌク遅延の補償は、オンラむンゲヌム開発の重芁な郚分です。このトピックに぀いお、私はここHabréに関する䞀連の蚘事を繰り返し読みたした。垆船の戊いの堎合、遅延補償は簡単ですが、劥協する必芁がありたす。



補間は垞にクラむアントで実行されたす-デヌタが既に取埗されおいる2぀の瞬間の間のゲヌム䞖界の状態の蚈算。わずかな時間の䜙裕があるため、突然のゞャンプの可胜性が䜎くなり、ネットワヌクの倧幅な遅延ず新しいデヌタの欠劂により、補間は倖挿に眮き換えられたす。倖挿はあたり正確な結果にはなりたせんが、プロセッサにずっおは安䟡であり、船の動きがサヌバヌでどのように実装されおいるかに䟝存したせん。もちろん、状況を救うこずもできたす。



ラグの問題を解決する堎合、ゲヌムずそのペヌスに倧きく䟝存したす。スムヌズなアニメヌションず特定の時点でのゲヌムの䞖界の状態ぞの画像の正確な察応を優先しお、プレむダヌのアクションに察する迅速な応答を犠牲にしたす。唯䞀の䟋倖は、ボタンを抌すずすぐに倧砲の斉射が行われるこずです。残りは宇宙の法則ず船の乗組員からのラム酒の䜙剰によるものです:)



フロント゚ンド



残念ながら、クラスやメ゜ッドの明確な構造や階局はありたせん。すべおのJSは、ある意味で同等の独自の機胜を持぀オブゞェクトに分割されたす。私の以前のプロゞェクトのほずんどすべおはこれより論理的でした。これは、最初の目暙が、ゲヌムのむンタヌフェむスず芖芚的コンポヌネントに泚意を払うこずなく、サヌバヌずネットワヌクの盞互䜜甚でゲヌムの䞖界モデルをデバッグするこずであったためでもありたす。3Dを远加するずきに、文字通り既存のテストバヌゞョンに远加したした。倧たかに蚀えば、2DのdrawShip関数をたったく同じ3Dに眮き換えたしたが、友奜的な方法で構造党䜓を修正し、将来の倉曎の基瀎を準備する䟡倀はありたした。



3D船



Three.jsは、さたざたな圢匏の既補の3Dモデルの䜿甚をサポヌトしおいたす。テクスチャずアニメヌションを埋め蟌めるGLTF / GLB圢匏を自分で遞択したした。開発者は「すべおのテクスチャがロヌドされおいるか」ず疑問に思わないでください。



これたで3D゚ディタを扱ったこずはありたせん。論理的なステップは、倧砲の斉射のアニメヌションが埋め蟌たれた垆船の3Dモデルを䜜成するタスクずのフリヌランス亀換の専門家に連絡するこずでした。しかし、自分で完成したスペシャリストモデルの小さな倉曎に抵抗するこずはできず、Blenderでモデルをれロから䜜成するこずになりたした。テクスチャがほずんどない䜎ポリゎンモデルを䜜成するのは簡単で、専門家の既補のモデルがなければ、特定のタスクに必芁なもの少なくずも道埳的に:)を3D゚ディタヌで調べるこずは困難です。







シェヌダヌの神ぞのシェヌダヌ



シェヌダヌが必芁な䞻な理由は、レンダリング䞭にビデオカヌド䞊のオブゞェクトのゞオメトリを操䜜できるこずです。これにより、パフォヌマンスが向䞊したす。Three.jsでは、独自のシェヌダヌを䜜成できるだけでなく、いく぀かの䜜業を行うこずもできたす。



船、動的氎面、たたは静的海底ぞのダメヌゞをアニメヌション化するためのパヌティクルシステムを䜜成するずきに䜿甚したメカニズムたたは方法は同じです。特別なShaderMaterialは、そのシェヌダヌそのGLSLコヌドを䜿甚するための簡略化されたむンタヌフェむスを提䟛し、BufferGeometryを䜿甚するず、任意のデヌタからゞオメトリを䜜成できたす...



空の空癜、同じような方法で3Dオブゞェクトを䜜成、コピヌ、補足、倉曎するのに䟿利なコヌド構造



コヌドを衚瀺
let vs = `
	attribute vec4 color;
	varying vec4 vColor;

	void main(){
		vColor = color;
		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
		// gl_PointSize = 5.0; // for particles
	}
`;
let fs = `
	uniform float opacity;
	varying vec4 vColor;

	void main() {
		gl_FragColor = vec4(vColor.xyz, vColor.w * opacity);
	}
`;

let material = new THREE.ShaderMaterial( {
	uniforms: {
		opacity: {value: 0.5}
	},
	vertexShader: vs,
	fragmentShader: fs,
	transparent: true
});

let geometry = new THREE.BufferGeometry();

//let indices = [];
let vertices = [];
let colors = [];

/* ... */

//geometry.setIndex( indices );
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 4 ) );

let mesh = new THREE.Mesh(geometry, material);




船の損傷



船の損傷のアニメヌションは、サむズず色が倉化する移動する粒子であり、その動䜜は属性ずGLSLシェヌダヌコヌドによっお決たりたす。パヌティクルゞオメトリずマテリアルの生成は事前に発生したす。その埌、各船ごずに損傷パヌティクルの独自のむンスタンスメッシュが䜜成されたすゞオメトリはすべおに共通であり、マテリアルが耇補されたす。かなりの数のパヌティクル属性がありたすが、䜜成されたシェヌダヌは、ゆっくりず移動する倧きなダストクラりド、急速に飛散するデブリ、および火のパヌティクルを同時に実装したす。これらのアクティビティは、船ぞの損傷の床合いによっお異なりたす。







æµ·



海もShaderMaterialを䜿甚しお実装されたす。各頂点は正匊波に沿っお3方向すべおに移動し、ランダムな波を圢成したす。属性は、運動の各方向の振幅ず正匊波の䜍盞を定矩したす。



氎の色を倚様化し、ゲヌムをより面癜く楜しいものにするために、底ず島を远加するこずにしたした。䞋郚の色は、高さ/深さに䟝存し、氎面を照らし、暗い領域ず明るい領域を䜜成したす。



海底は2段階で䜜成された高さマップから䜜成されたす。最初に、島のない底がグラフィカル゚ディタヌで䜜成され私の堎合、ツヌルはレンダリング->雲ずガりスがかし、次に島はjsFiddleでCanvas JSオンラむンを䜿甚しおランダムな順序で远加されたした円を描いおがかしたす。いく぀かの島は䜎いです、それらを通しおあなたは敵を撃぀こずができたす、他は䞀定の高さを持っおいたす、ショットはそれらを通過したせん。高さマップ自䜓に加えお、出力では、サヌバヌ䞊の物理のアむランド䜍眮ずサむズに関するjson圢匏のデヌタを受け取りたす。







次は䜕ですか



ゲヌムの開発には倚くの蚈画がありたす。䞻なものは新しいゲヌムモヌドです。小さいもの-WebGLずJSのパフォヌマンス制限を考慮しお、氎の圱/反射を考え出したす。私はすでにクラヌケンを目芚めさせる機䌚に぀いお述べたした:)圌らの蓄積された経隓に基づく郚屋ぞのプレヌダヌの統合はただ実装されおいたせん。明らかな、しかしそれほど高くない優先順䜍の改善は、海底ず島のいく぀かのマップを䜜成しお、新しい戊いのためにそれらの1぀をランダムに遞択するこずです。



シヌンを「メモリに」繰り返し描画し、すべおのデヌタを1぀の画像に結合するこずで倚くの芖芚効果を䜜成できたす実際、埌凊理ず呌ぶこずができたすが、クラむアントがただブラりザであるため、この方法ではクラむアントの負荷が増加するこずはありたせん。ネむティブアプリではなく。たぶん、ある日、私はこのステップを決定したす。



たた、私が答えるのが難しいず思う質問もありたす。安䟡な仮想サヌバヌに䜕人のオンラむンプレヌダヌが耐えるこずができるか、少なくずも特定の数の関心のあるプレヌダヌを収集するこずが可胜かどうか、およびその方法です。



むヌスタヌ゚ッグ



それほど倚くの感情を䞎えた叀いコンピュヌタゲヌムを芚えたくない人はいたすか今たで䜕床も䜕床も䜕床もゲヌムCorsairs 2別名Sea Dogs 2を再生するのが倧奜きです。私はゲヌムに秘密を远加せざるを埗ず、「コルセア2」を明瀺的か぀間接的に連想させたす。すべおのカヌドを明らかにするわけではありたせんが、ヒントを䞎えたす。私のむヌスタヌ゚ッグは、海を探玢しおいるずきに芋぀けるこずができる特定のオブゞェクトです無限の海をはるかに越えお航行する必芁はありたせん。オブゞェクトは劥圓な範囲内ですが、芋぀ける確率は高くありたせん。むヌスタヌ゚ッグは損傷した船を完党に修埩したす。



どうした



ミニッツビデオ2台のデバむスからテスト





ゲヌムぞのリンクhttps : //sailfire.pw



お問い合わせフォヌムもあり、メッセヌゞは電報で私に送信されたすhttps :

//sailfire.pw/feedback/ニュヌスやアップデヌトに遅れないようにしたい人ぞのリンクVK Public、電報チャネル



All Articles