今回、何かが私をより深く掘り下げた。 ライブラリを知るために何かを実装するよりも良い方法はないと判断し、自由な夜を過ごすために、私は単純なものを書くことにしました。例えば、自分の興味のためではなく、知り合いのために、子供時代の私のお気に入りのアルカノイド(ブリックアウト)を書くことにしました。
これはハーバーに関する私の最初の記事です。
この記事の意味は、XNAを使用してゲームの作成を開始することがいかに簡単かを示すことであり、実際、このプラットフォームをさらに研究するためのインセンティブを提供することです。 したがって、それは本格的なゲームのふりをするものではなく、グラフィックは私からのアーティストのようなものではありません。 物理学はより現実的かもしれませんが、これはこの記事の範囲を超えています。ゲーム開発に興味がある人は、ネットワーク上で多くの価値のある(そうではない)資料を見つけると確信しています。
ソースはここからダウンロードできます
それでは、Microsoft XNAとは正確には何ですか?
Microsoft XNAは、Microsoft Managed Runtime Environmentでマルチプラットフォームの2Dおよび3Dゲームを開発するためのツールキットおよびライブラリです。 サポートされるプラットフォームは、Windows、Microsoft Xbox 360、およびMicrosoft Zuneです。 理論的には、任意の.Net言語、任意のIDEで記述できますが、正式にサポートされているのはC#とXNA Game Studio ExpressおよびVisual Studio 2005以降のすべてのバージョンのみです。 XNAは、最小限の変更でサポートされているプラットフォームにゲームを移植する機能も提供します。
執筆時点での最新バージョンは、 Microsoft XNA Game Studio 3.1(73.2 MB)です。
プロジェクト作成
新しいプロジェクトを作成しましょう-XNA Game Studio 3.1-Windowsゲーム(3.1)
ウィザードはゲームのスケルトンを作成します:
私たちにとって最大の関心事は、ゲームを開発するMicrosoft.Xna.Framework.Gameから継承されたGame1クラスを定義するGame1.csファイルです。
次のGameメソッドは、Game1クラスでオーバーライドされます。
void Initialize()-ゲームが開始する前にリソースを初期化するために一度呼び出されます
void LoadContent()-一度呼び出され、コンテンツ(スプライトなど)のロードに使用されます
void UnloadContent()-一度呼び出され、コンテンツのアップロードに使用されます
void Update(GameTime gameTime)-このメソッドは、ゲームの実際のロジック、衝突処理、キーボードまたはジョイスティックイベントの処理、オーディオの再生などを実装します。
void Draw(GameTime gameTime)-競技場を描くために呼び出されます。
現時点では、コンパイルされたゲームは次のようになります
コンテンツを追加する
ゲームリソースを追加します。この場合、レンガ、ラケット、ボールの背景画像-コンテンツ(右クリック)->追加->既存のアイテム...
Asset Nameプロパティに注意してください。これを使用して、さらにアニメーションを作成するために必要なTexture2Dオブジェクトを作成します。
競技場の背景を描く
競技場の背景の画像をダウンロードします。
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
private Rectangle _viewPortRectangle; // private Texture2D _background; // protected override void LoadContent() { <... skip ...> // _viewPortRectangle = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); _background = Content.Load<Texture2D>( @"background" ); <... skip ...> } * This source code was highlighted with Source Code Highlighter .
背景の描画
*このソースコードは、 ソースコードハイライターで強調表示されました。
- 保護された オーバーライド void Draw(GameTime gameTime)
- {
- GraphicsDevice.Clear(Color.CornflowerBlue);
- spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
- //背景を描きます
- spriteBatch.Draw(_background、_viewPortRectangle、Color.White);
- spriteBatch.End();
- base .Draw(gameTime);
- }
SpriteBatch.Beginメソッドは、スプライトをレンダリングするためにグラフィックデバイスを準備し、SpriteBatch.Endは描画プロセスを完了し、デバイスを初期状態に戻します。 すべてのSpriteBatch.Drawメソッドは、SpriteBatch.Begin-SpriteBatch.Endで囲む必要があります。
ゲームオブジェクトを作成する
ゲームオブジェクトのいずれかをカプセル化するGameObjectクラスを作成しましょう。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- Microsoft.Xna.Framework を使用 。
- Microsoft.Xna.Framework を使用します。 グラフィックス
- 名前空間アルカノイド
- {
- パブリック クラス GameObject
- {
- public Texture2D Sprite { 取得 ; セット ; } //スプライト
- パブリック Vector2の位置。 //位置
- パブリック Vector2 Velocity; //速度
- public int Width { get { return Sprite.Width; }} //幅
- public int Height { get { return Sprite.Height; }} //高さ
- パブリック ブール IsAlive { get ; セット ; } //オブジェクトは生きているか
- public Rectangle Bounds //オブジェクト境界
- {
- 得る
- {
- 新しい Rectangle(( int )Position.X、( int )Position.Y、Width、Height);
- }
- }
- //水平軸に沿って動きを拡大
- public void ReflectHorizontal()
- {
- Velocity.Y = -Velocity.Y;
- }
- //垂直軸に沿って動きを拡大します
- public void ReflectVertical()
- {
- Velocity.X = -Velocity.X;
- }
- パブリック GameObject(Texture2Dスプライト)
- {
- スプライト=スプライト;
- IsAlive = true ;
- 位置= Vector2.Zero;
- 速度= Vector2.Zero;
- }
- }
- }
ラケットのレンダリングとアニメーション
最初に、ラケットを表すオブジェクトを作成し、それを競技場の中央から下端から少し高く配置します。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- プライベート GameObject _paddle; //ラケット
- 保護された オーバーライド void LoadContent()
- {
- <...スキップ...>
- //ラケットを作成します。開始位置は競技場の中央、下端より高くなります
- _paddle = new GameObject(Content.Load <Texture2D>( @ "paddle" ));
- _paddle.Position = new Vector2((_ viewPortRectangle.Width-_paddle.Width)/ 2、
- _viewPortRectangle.Height-_paddle.Height-20);
- <...スキップ...>
- }
画面にラケットを描く
*このソースコードは、 ソースコードハイライターで強調表示されました。
- 保護された オーバーライド void Draw(GameTime gameTime)
- {
- <...スキップ...>
- spriteBatch.Draw(_paddle.Sprite、_paddle.Position、Color.White);
- <...スキップ...>
- }
この段階で、アプリケーションをコンパイルすると、次のようになります。
ラケットをキーストロークに応答させると便利です。このため、次のコードをUpdateメソッドに追加します
*このソースコードは、 ソースコードハイライターで強調表示されました。
- 保護された オーバーライド void更新(GameTime gameTime)
- {
- <...スキップ...>
- KeyboardState keyboardState = Keyboard.GetState();
- //ラケットを右に移動
- if (keyboardState.IsKeyDown(Keys.Right))
- _paddle.Position.X + = 6f;
- //ラケットを左に移動します
- if (keyboardState.IsKeyDown(Keys.Left))
- _paddle.Position.X-= 6f;
- //ラケットの動きを競技場に制限する
- _paddle.Position.X = MathHelper.Clamp(_paddle.Position.X、0、_viewPortRectangle.Width-_paddle.Width);
- <...スキップ...>
- }
レンガの描画
実際に壊すブリックを表すGameObject配列を作成します
*このソースコードは、 ソースコードハイライターで強調表示されました。
- private int _brickPaneWidth = 10; //幅で描画する糸杉の数
- private int _brickPaneHeight = 5; //高さで描画する糸杉の数
- プライベート Texture2D _brickSprite; //レンガのスプライト
- プライベート GameObject [、] _bricks; //レンガの配列
LoadContent()メソッドに次のコードを追加します
*このソースコードは、 ソースコードハイライターで強調表示されました。
- 保護された オーバーライド void LoadContent()
- {
- <...スキップ...>
- //ブリックの配列を作成します
- _brickSprite = Content.Load <Texture2D>( @ "brick" );
- _bricks = 新しい GameObject [_brickPaneWidth、_brickPaneHeight];
- for ( int i = 0; i <_brickPaneWidth; i ++)
- {
- for ( int j = 0; j <_brickPaneHeight; j ++)
- {
- _bricks [i、j] = 新しい GameObject(_brickSprite)
- {
- 位置= 新しい Vector2(i * 55 + 120、j * 25 + 100)
- };
- }
- }
- <...スキップ...>
- }
レンガの配列を描画し、レンガが「生きている」場合、つまりレンダリングが行われます。 ボールで壊れない
*このソースコードは、 ソースコードハイライターで強調表示されました。
- 保護された オーバーライド void Draw(GameTime gameTime)
- {
- <...スキップ...>
- //レンガを描く
- foreach (_bricksのvar brick)
- if (brick.IsAlive)
- spriteBatch.Draw(brick.Sprite、brick.Position、Color.White);
- <...スキップ...>
- }
この段階での競技場は次のとおりです
ボール描画
ボールオブジェクトを作成する
*このソースコードは、 ソースコードハイライターで強調表示されました。
- プライベート GameObject _ball; //ボール
- 保護された オーバーライド void LoadContent()
- {
- <...スキップ...>
- //ラケットの中央の初期位置であるボールを作成し、
- //方向を開始-右、上
- _ball = new GameObject(Content.Load <Texture2D>( @ "ball" ));
- _ball.Position = new Vector2((_ viewPortRectangle.Width-_ball.Width)/ 2、
- _viewPortRectangle.Height-_paddle.Height-_ball.Height-20);
- _ball.Velocity = new Vector2(3、-3);
- <...スキップ...>
- }
ボールをアニメートするには、新しいUpdateBall()メソッドを追加し、Update()メソッドで呼び出します。 レンガとラケットとのボールの衝突を処理するために、今後このメソッドが必要になります
*このソースコードは、 ソースコードハイライターで強調表示されました。
- プライベート void UpdateBall()
- {
- _ball.Position + = _ball.Velocity;
- }
- 保護された オーバーライド void更新(GameTime gameTime)
- {
- <...スキップ...>
- //ボールを移動します
- UpdateBall();
- <...スキップ...>
- }
ボールを描くには、次のコードをDraw()メソッドに追加します
*このソースコードは、 ソースコードハイライターで強調表示されました。
- 保護された オーバーライド void Draw(GameTime gameTime)
- {
- <...スキップ...>
- //ボールを描く
- spriteBatch.Draw(_ball.Sprite、_ball.Position、Color.White);
- <...スキップ...>
- }
現時点では、ほぼ完全に終了した競技場がありますが、衝突処理がなければ、ボールはすぐに競技場から飛び出します。 競技場、レンガ、ラケットにボール衝突処理を追加します
衝突処理
オブジェクトの衝突の場所を決定し、ボールの飛行方向を変更する新しいメソッドを作成します。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- //衝突の側面を特定し、ボールの飛行の方向を反映します
- public void Collide(GameObject gameObject、Rectangle rect2)
- {
- //オブジェクトは上下に衝突し、水平方向の飛行方向を反映します
- if (rect2.Left <= gameObject.Bounds.Center.X && gameObject.Bounds.Center.X <= rect2.Right)
- gameObject.ReflectHorizontal();
- //左右に衝突したオブジェクト、飛行方向を垂直に反映
- else if (rect2.Top <= gameObject.Bounds.Center.Y && gameObject.Bounds.Center.Y <= rect2.Bottom)
- gameObject.ReflectVertical();
- }
UpdateBall()メソッドに次のコードを追加します
*このソースコードは、 ソースコードハイライターで強調表示されました。
- プライベート void UpdateBall()
- {
- //ボールの将来の位置。オブジェクトの表面にボールが「くっつく」のを防ぐ必要があります
- Rectangle nextRect = 新しい Rectangle(( int )(_ ball.Position.X + _ball.Velocity.X)、
- ( int )(_ ball.Position.Y + _ball.Velocity.Y)、
- _ball.Width、_ball.Height);
- //競技場の上端との衝突
- if (nextRect.Y <= 0)
- _ball.ReflectHorizontal();
- //ボールが競技場の下端に当たると、ボールは「死ぬ」
- if (nextRect.Y> = _viewPortRectangle.Height-nextRect.Height)
- {
- _ball.IsAlive = false ;
- }
- //競技場の左端または右端とボールの衝突
- if ((nextRect.X> = _viewPortRectangle.Width-nextRect.Width)|| nextRect.X <= 0)
- {
- _ball.ReflectVertical();
- }
- //ラケットとボールの衝突
- if (nextRect.Intersects(_paddle.Bounds))
- 衝突(_ball、_paddle.Bounds);
- //レンガと衝突ボール
- foreach (_bricksのvar brick)
- {
- if (nextRect.Intersects(brick.Bounds)&& brick.IsAlive)
- {
- brick.IsAlive = false ;
- 衝突(_ball、brick.Bounds);
- }
- }
- _ball.Position + = _ball.Velocity;
- }
どうしたの
もちろん、ゲームには物理学はありません。控えめに言っても、ボールが動いているラケットと衝突すると、スティックすることがあります。 ただし、この記事の意味はMicrosoft XNA Game Studio環境に精通していることであり、このルーチンに対応しているため、開発者はゲームのロジックに集中することができます。
ソースはここからダウンロードできます
追加のリソース:
creators.xna.com
XNAWiki
PS。 招待してくれてありがとう。
PPS XNAに転送されたカルマをありがとう
テキストはHabraで準備されます