Posts from the ‘Македонски’ Category

Развивање 2Д Игри За Windows 8 Со MonoGame Четврт Дел–Дотерување

Во последниот дел од овој серијал ќе ја дотераме нашата игра. Прво ќе напишеме неколку линии за ‘вртење’ на топчето. Потоа, ќе додадеме SpriteFont кој што се користи за пишување текст за да ги нацртаме индикаторите за поени. Следно, ќе ставиме една линија на средина за да ја поделиме површината за играње на два дела, па ќе ставиме звуци за колизии и на крај ќе додадеме Splash Screen и логоа.

Вртење на Топчето

Отворете ја Game1.cs класата и додадете нова константа:

const float SPIN = 2.5f;

 

Следно, во Update методот веднаш после линиите за движење со Touch, додадете ги следните if-тестови:

player1.Move(player1TouchVelocity);
player2.Move(player2TouchVelocity);

if (player1TouchVelocity.Y > 0f)
{
	player1Velocity = player1TouchVelocity;
}
if (player2TouchVelocity.Y > 0f)
{
	player2Velocity = player2TouchVelocity;
}

if (player1Velocity.Y != 0)
{
	player1Velocity.Normalize();
}
if(player2Velocity.Y != 0)
{
	player2Velocity.Normalize();
}

 

Во нашиот случај, доколку играчите користат touch, ќе забележите дека брзината на играчите не е дефинирана, туку во зависност од брзината на влечење, се мрда и играчот. Додека, со тастатура, има една и единствена брзина дефинирана во константата KEYBOARD_PADDLE_SPEED. За да не се дозволи играчите на touch да можат повеќе или помалку да го ‘вртат’ топчето, брзините ќе ги нормализираме за да се добие насоката на движење на играчот.

Значи прво проверуваме дали постои инпут со touch, доколку постои ја зачувуваме таа вредност и потоа ја нормализираме.

Во истиот Update метод, во if-тестовите кои што проверуваат дали има колизија помеѓу играчите и топчето, додадете ги линиите како што е покажано подолу:

if (GameObject.CheckPaddleBallCollision(player1, ball))
{
	ball.Velocity.X = Math.Abs(ball.Velocity.X);
	ball.Velocity += player1Velocity * SPIN;
}

if (GameObject.CheckPaddleBallCollision(player2, ball))
{
	ball.Velocity.X = -Math.Abs(ball.Velocity.X);
	ball.Velocity += player2Velocity*SPIN;
}

 

Откако ја менуваме насоката на топчето, на брзината ја додаваме насоката на играчот помножена со константата за ‘вртење’ на топчето.

Притиснете F5 или Debug –> Start Debugging и тестирајте. Ќе забележите дека во зависност од тоа како го удирате топчето, тоа или забрзува или забавува.

Слободно можете да ги менувате константите во зависност од тоа дали сакате топчето да има поголема почетна брзина, да има поголемо вртење и слично.

Индикатори за Поени

Најпрво превземете и инсталирајте го 8Bit Wonder фонтот од тука.

Сега ќе треба да се повторат чекорите за внесување надворешни фајлови од вториот дел за да ставиме SpriteFont во нашата игра.

Пуштете го Visual Studio 2012 Express for Windows Phone и отворете го PongContent проектот. Притиснете десен-клик на Content проектот па Add –> New Item.

 

Одберете лево Visual C#, потоа одберете SpriteFont, крстете го RetroFont и притиснете Add.

Откако ќе притиснете Add, ќе ви се отвори RetroFont.spritefont фајлот во Visual Studio каде што може да ги променувате неговите параметри како име на фонт, големина, стил итн.

Направете ги следните промени:

<FontName>8Bit Wonder</FontName>

<Size>32</Size>

<Style>Bold</Style>

Откако ќе ги промените вредностите, притиснете Build –> Build Solution. Откако ќе се комплетира компајлирањето, исклучете го Visual Studio 2012 Express for Windows Phone.

Вратете се на PongClone проектот, притиснете десен-клик на ‘Content’ фолдерот, Add –> Existing item.

Навигирајте во:

…\Documents\Visual Studio 2012\Projects\PongContent\PongContent\PongContent\bin\Windows Phone\Debug\Content

Одберете го RetroFont.xnb и притиснете Add.

Сега, селектирајте го RetroFont и променете го Build Action од None во Content.

Отворете ја Player.cs класата и додадете ја следната променлива:

public int Score;

Отворете ја Game1.cs класата, декларирајте нова SpriteFont променлива по декларацијата на играчите и топчето:

Player player1;
Player player2;
Ball ball;

SpriteFont retroFont;

Во LoadContent методот додадете ја следната линија за вчитување на SpriteFont-от:

retroFont = Content.Load<SpriteFont>("RetroFont");

Во Update методот, сменете ги if-тестовите за повторно лансирање на топчето во следното:

if (ball.Position.X + ball.Texture.Width < 0)
{
	ball.Launch(BALL_START_SPEED);
	player2.Score++;
}

if (ball.Position.X > ScreenWidth)
{
	ball.Launch(BALL_START_SPEED);
	player1.Score++;
}

Значи, доколку топчето излезе од левата страна, вториот играч добива еден поен. Доколку топчето излезе од десната страна, првиот играч добива еден поен.

Во Draw методот, помеѓу _spriteBatch.Begin() и player1.Draw(_spriteBatch) додадете ја линијата за цртање на поените:

_spriteBatch.Begin();
_spriteBatch.DrawString(retroFont, player1.Score + "        " + player2.Score,new Vector2(ScreenWidth / 2 -retroFont.MeasureString(player1.Score + "        " + player2.Score).X / 2,0), Color.Cyan);
player1.Draw(_spriteBatch);

DrawString методот го прима SpriteFont објектот, текстот што сакаме да го напишеме, позицијата на текстот (во нашиот случај во зависност од должината на string-от позицијата ќе се променува, а должината на string-от ја мериме со MeasureString методот), и бојата на текстот.

Притиснете F5 или Debug –> Start Debugging за да тестирате. Ќе забележите на горната страна нацртани се индикаторите за поени на играчите.

Сега може да ја додадеме и линијата на средина за да ја поделиме површината на два дела.

Во Game1.cs веднаш после декларацијата на SpriteFont retroFont; додадете една текстура која што ќе ја нацртаме на средина:

SpriteFont retroFont;
Texture2D middleTexture;

Во LoadContent методот додадете ја следната линија:

middleTexture = Content.Load<Texture2D>("Middle");

Во Draw методот, после _spriteBatch.Begin() додадете ја линијата за цртање на текстурата:

_spriteBatch.Draw(middleTexture,new Rectangle(ScreenWidth / 2 - middleTexture.Width / 2, 0, middleTexture.Width,ScreenHeight), null, Color.White);

Забележувате дека сега користиме друг overload на Draw методот. Бидејќи Middle текстурата ни е 4 пиксели широка и 1 пиксел висока (4×1), со помош на Rectangle ќе ја рашириме текстурата од горе до долу. Кога се користи Rectangle за цртање на објекти на екран, без разлика колкава е големината на текстурата, таа се раширува за да ја опфати големината на Rectangle објектот.

Притиснете F5 или Debug –> Start Debugging за да ја видите новата текстура.

Звучни Ефекти

Бидејќи звуците веќе ги ставивме во нашиот проект во вториот дел кога ги префрливме сите екстерни фајлови, сега нема потреба од повторно компајлирање.

За менаџирање на звучните ефекти ќе креираме нова статична класа, ‘SoundManager’.

Притиснете десен-клик на ‘Classes’, Add –> Class… , крстете ја класата ‘SoundManager’ (без наводници) и притиснете Add.

Преправете ја класата во следното:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;

namespace PongClone
{
    public static class SoundManager
    {
        public static SoundEffect BallWallCollisionSoundEffect;
        public static SoundEffect PaddleBallCollisionSoundEffect;

        public static void LoadSounds(ContentManager Content)
        {
            BallWallCollisionSoundEffect = Content.Load<SoundEffect>("BallWallCollision");
            PaddleBallCollisionSoundEffect = Content.Load<SoundEffect>("PaddleBallCollision");
        }
    }
}

Забележувате дека имаме две променливи кои што ќе ги чуваат звуците за колизија помеѓу ‘ѕидовите’ и топчето, и помеѓу играчите и топчето. Потоа имаме еден статичен метод кој што прима ContentManager објект кој што се користи за вчитување на звуците.

Отворете ја Game1.cs класата и во LoadContent додадете ја следната линија:

SoundManager.LoadSounds(Content);

Потоа, во Update методот, преправете ги if-тестовите за колизија помеѓу играчите и топчето во следното:

if (GameObject.CheckPaddleBallCollision(player1, ball))
{
	ball.Velocity.X = Math.Abs(ball.Velocity.X);
	ball.Velocity += player1Velocity * SPIN;
	SoundManager.PaddleBallCollisionSoundEffect.Play();
}

if (GameObject.CheckPaddleBallCollision(player2, ball))
{
	ball.Velocity.X = -Math.Abs(ball.Velocity.X);
	ball.Velocity += player2Velocity*SPIN;
	SoundManager.PaddleBallCollisionSoundEffect.Play();
}

Значи, штом има колизија помеѓу некој од играчите и топчето, го активираме звукот.

Отворете ја Ball.cs класата и преправете го CheckWallCollision методот во следното:

public void CheckWallCollision()
{
	if (Position.Y < 0)
	{
		Position.Y = 0;
		Velocity.Y *= -1;
		SoundManager.BallWallCollisionSoundEffect.Play();
	}
	if (Position.Y + Texture.Height > Game1.ScreenHeight)
	{
		Position.Y = Game1.ScreenHeight - Texture.Height;
		Velocity.Y *= -1;
		SoundManager.BallWallCollisionSoundEffect.Play();
	}
}

Исто и тука забележувате дека штом се детектира колизија помеѓу топчето и горната или долната страна на екранот, го активираме звукот.

Притиснете F5 или Debug –> Start Debugging за да ги тестирате последните промени.

Splash Screen и Логоа

Превземете го .rar фајлот од тука и екстрактирајте ги сликите во следниот фолдер:

…\Documents\Visual Studio 2012\Projects\PongClone\PongClone\Assets

Кога ќе ве праша дали сакате да ги промените старите слики со новите, прифатете.

Во Visual Studio 2012, отворете го Package.appxmanifest фајлот (покажан на сликата)

Ке ви се отвори нов прозорец со опции за името на играта, можност за промена на логоата и слично. Притиснете на Splash Screen и во Background Color напишете black.

Притиснете F5 или Debug –> Start Debugging за да тестирате. Ќе видите дека сега имате нов Splash Screen.

Исто така на вашиот Start Screen ќе забележите ново иконче за играта.

Честито, ја комплетиравте вашата прва Windows 8 игра со MonoGame.

Мојот Solution може да го превземете од тука.

Напомена: Ќе треба да ги сетирате референците до MonoGame за да го тестирате мојот Solution.

Се надевам ви се допадна овој мини серијал. Доколку имате некакви прашања, оставете коментар подолу. Би сакал да им се заблагодарам на дечките од 3D Buzz, бидејќи пред повеќе од една година кога го учев XNA фрејмворкот, една од поголемите задачи беше креирање на Pong игра.

Развивање 2Д Игри За Windows 8 Со MonoGame Трет Дел–Логика На Игра

Стигнавме до најинтересниот дел (барем за мене 🙂 ) од овој серијал. По цртањето на објектите кое што беше опфатено во вториот дел, во овој дел ќе додадеме движење, инпут (со тастатура и допир) и колизии.

Движење

Прво, ќе имплементираме движење на топчето бидејќи топчето е независно од надворешен инпут.

Отворете ја GameObject.cs класата и додадете го методот Move:

public virtual void Move(Vector2 amount)
{
	Position += amount;
}

 

Движењето во 2Д игри е прилично едноставно. Се што се прави е, на вектор за позиција се додава друг вектор за да се добие нова позиција. Со повторување на овој метод 30 пати во секунда, ќе се добие некакво движење.

На првата линија забележувате искористен е зборот virtual. Овој метод ќе го искористиме во наследените класи Player и Ball со тоа што на двете класи ќе им додадеме уште неколку линии кои што не се заеднички меѓу нив.

Отворете ја Ball.cs класата и преправете ја во следното:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;

namespace PongClone
{
	public class Ball : GameObject
	{
		public Vector2 Velocity;
		public Random random;

		public Ball()
		{
			random = new Random();
		}
	}
}

 

Топчето ќе има променлива брзина, затоа ни треба еден вектор кој што ќе ја прати брзината (и насоката) на топчето. Random објектот ќе се користи за лансирање на топчето на левата или десната страна (50% веројатност на едната страна, 50% веројатност на другата страна). Конструкторот на линиите 15, 16, 17 и 18 се користи за креирање на Random објектот кој што ќе го користиме во Launch методот.

Додадете го следниот Launch метод во Ball.cs класата:

public void Launch(float speed)
{
	Position = new Vector2(Game1.ScreenWidth / 2 - Texture.Width / 2, Game1.ScreenHeight / 2 - Texture.Height / 2);
	// get a random + or - 60 degrees angle to the right
	float rotation = (float) ( Math.PI/2 + (random.NextDouble() * (Math.PI/1.5f) - Math.PI/3));

	Velocity.X = (float) Math.Sin(rotation);
	Velocity.Y = (float)Math.Cos(rotation);

	// 50% chance whether it launches left or right
	if (random.Next(2) == 1)
	{
		Velocity.X *= -1; //launch to the left
	}

	Velocity *= speed;
}

 

Не плашете се од математиката во овој метод, многу е едноставна, ќе ви објаснам што се случува на секоја линија.

Како што може да видите на првата линија, Launch методот добива параметар за брзина (има разлика помеѓу speed и Velocity; speed е брзина скалар, velocity е брзина со насока, вектор). Оваа брзина (speed) ќе ни ја претставува почетната брзина на топчето.

Во третата линија, се сетира почетната позиција на топчето (во нашиот случај, на центарот на екранот).

Потоа, во линија 5 креираме променлива за вредност на ротација кој што потоа во линиите 7 и 8 се користи за да се добие аголот на кој што ќе се лансира топчето. Доколку ротацијата е 0, Sin(0) = 0, и Cos(0) = 1. Бидејќи вредноста која што произлегува од Sin функцијата ја ставаме во Velocity.X, а вредностa што произлегува од Cos функцијата ја ставаме во Velocity.Y , топчето ќе се лансира надолу. Како што кажав на претходниот пост, (0,0) на екранот се наоѓа на горниот лев агол, тоа значи дека позитивната страна на Y оди надолу.

Најпрво на вредноста за ротација му даваме вредност Math.PI / 2 со која што ќе добиеме лансирање на десната страна бидејки Pi / 2 = 90 степени, Sin(90 степени) = 1, Cos(90 степени) = 0. Потоа на таа вредност додаваме нова вредност со користење на Random објектот за да генерираме вредност помеѓу +60 и –60 степени (во нашиот случај рачунаме со радијани, поради едноставност, бројките во ова објаснување ги конвертирам во степени).

Како дојдовме до +60 и –60? random.NextDouble() генерира вредности помеѓу 0.0 и 1.0. Таа вредност ја множиме со Math.PI / 1.5f (120 степени). Сега добиваме вредности од 0 до 120 степени. Затоа, на крај имаме – Math.PI / 3 (60 степени) со кој што го добиваме посакуваниот интервал (-60,+60)

Сега топчето иако ќе се лансира по случаен агол измеѓу –60 и +60 степени, постојано ќе се лансира на десната страна. Во линија 11 генерираме цел број помеѓу 1 и 0. Шансите да се добие 1 или 0 се 50-50. Доколку се добие 1, вредноста на Velocity.X ја множиме со –1 со што ја променуваме насоката на лансирање од десно на лево.

Конечно вектор брзината (Velocity) ја множиме со скаларната брзина (speed) за да ја добиеме конечната почетна брзина на топчето.

Напомена: Доколку оваа математика не ви е јасна, откако ќе го напишеме кодот во Game1.cs, може да се вратите на овој метод и да ги промените вредностите кои што се во rotation. Почнете со давање на вредност 0 и зголемувајте/намалувајте од тука за да видите што се случува со аголот на лансирање. Ако повторно не ви е јасно, слободно оставете коментар подолу.

Отворете ја Game1.cs класата и најгоре каде што ја дефиниравме првата константа PADDLE_OFFSET = 70, додадете нова константа за почетна брзина на топчето:

const float BALL_START_SPEED = 8f;

Избришете ја следната линијата за сетирање на позицијата на топчето во LoadContent бидејќи истата ја имаме во Launch методот:

ball.Position = new Vector2(ScreenWidth / 2 - ball.Texture.Width / 2, ScreenHeight / 2 - ball.Texture.Height / 2);

 

На тоа место ставете ја следната линија:

ball.Launch(BALL_START_SPEED);

 

Во Update методот, под линиите за ширина и висина на екранот, додадете ја линијата

ball.Move(ball.Velocity);

ScreenWidth = GraphicsDevice.Viewport.Width;
ScreenHeight = GraphicsDevice.Viewport.Height;
ball.Move(ball.Velocity);
base.Update(gameTime);

Оваа линија ќе го активира Move методот каде што се собираат векторите Position и Velocity, и резултатот се зачувува во Position.

Притиснете F5 или Debug –> Start Debugging за да ја пуштите апликацијата. Ќе забележите дека топчето се движи и после кратко време излегува од видното поле. Пред да преминеме на пишување логика за колизии, ќе го имплементираме инпутот за играчите.

Инпут

Најпрво ќе креираме нова класа која што ќе се користи за процесирање на инпутот од играчите. Притиснете десен клик на фолдерот ‘Classes’ Add –> Class… крстете ја новата класа ‘Input’ (без наводници).

Преправете ја Input.cs класата во следното:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;

namespace PongClone
{
    public static class Input
    {
        public static List<GestureSample> Gestures;

        static Input()
        {
            Gestures = new List<GestureSample>();
        }

    }
}

 

Ќе забележите дека се додадени неколку библиотеки кои што ќе се потребни за имплементирање на инпутот. Потоа ќе забележите дека креираме статична класа (линија 12). Тоа значи дека самата класа ни претставува еден и единствен објект (не ни требаат повеќе објекти за да се процесира инпут). Потоа во линија 14 декларираме една листа Gestures која што ќе ги чува сите инпути на допир (Touch). Во конструкторот static Input(), ја иницијализираме листата за да можеме да ја користиме покасно.

Прво ќе го напишеме методот за инпут од тастатура. Додадете го следниот метод во класата:

public static Vector2 GetKeyboardInputDirection(PlayerIndex playerIndex)
{
	Vector2 direction = Vector2.Zero;
	KeyboardState keyboardState = Keyboard.GetState(playerIndex);

	if (playerIndex == PlayerIndex.One)
	{
		if (keyboardState.IsKeyDown(Keys.W))
			direction.Y += -1;
		if (keyboardState.IsKeyDown(Keys.S))
			direction.Y += 1;
	}

	if (playerIndex == PlayerIndex.Two)
	{
		if (keyboardState.IsKeyDown(Keys.Up))
			direction.Y += -1;
		if (keyboardState.IsKeyDown(Keys.Down))
			direction.Y += 1;
	}
	return direction;
}

 

Oвој метод враќа Vector2 објект и прима еден параметар PlayerIndex со кој што се дефинира за кој играч станува збор (првиот, вториот итн.). Во третата линија иницијализираме еден вектор на (0,0) кој што ќе ја содржи насоката на движење. Во линија 4, декларираме KeyboardState променлива и ја земаме состојбата на тастатурата. Потоа во шестата линија проверуваме дали станува збор за првиот играч. Доколку одговорот е да, проверуваме дали буквата W е притисната. Ако е притисната, ја намалуваме вредноста на Y оската за 1 (Y се намалува ако се движиме нагоре). Истото се проверува и со буквата S за движење надолу. Доколку не станува збор за првиот играч, се проверуваат истите работи со различни копчиња (стрелките за горе и долу) за вториот играч. На крајот се враќа вредноста на векторот direction кој што ја содржи насоката. Насоката може да биде нагоре, надолу, или нема промена на местото ако нема никаков инпут.

Отворете ја Game1.cs класата и додадете уште една константа за брзината на играчите кога инпутот е преку тастатура:

const float KEYBOARD_PADDLE_SPEED = 10f;

 

Во Update методот, под линијата ball.Move(ball.Velocity); додадете ги следните линии:

ball.Move(ball.Velocity);

Vector2 player1Velocity = Input.GetKeyboardInputDirection(PlayerIndex.One) * KEYBOARD_PADDLE_SPEED;
Vector2 player2Velocity = Input.GetKeyboardInputDirection(PlayerIndex.Two) * KEYBOARD_PADDLE_SPEED;

player1.Move(player1Velocity);
player2.Move(player2Velocity);

 

Прво декларираме и ги иницијализираме брзините на играчите во два Vector2 променливи. Бидејќи методот што претходно го напишавме во инпут класата враќа вектор со насока, го множиме резултатот со константата каде што е дефинирана брзината. Потоа ги повикуваме Move методите за движење на играчите.

Притиснете F5 или Debug –> Start Debugging и тестирајте го движењето на играчите. Ќе забележите дека играчите го напуштаат видното поле, во следниот дел за колизии ќе ги поставиме границите на движење.

Пред да преминеме на колизии, најпрво ќе го имплементираме инпутот преку допир (Touch). Отворете ја Input.cs класата и додадете го следниот метод:

public static void ProcessTouchInput(out Vector2 player1Velocity, out Vector2 player2Velocity)
{
	Gestures.Clear();
	while (TouchPanel.IsGestureAvailable)
	{
		Gestures.Add(TouchPanel.ReadGesture());
	}
	player1Velocity = Vector2.Zero;
	player2Velocity = Vector2.Zero;

	foreach (GestureSample gestureSample in Gestures)
	{
		if (gestureSample.GestureType == GestureType.FreeDrag)
		{
			if (gestureSample.Position.X >= 0 && gestureSample.Position.X <= Game1.ScreenWidth / 2)
                        player1Velocity.Y += gestureSample.Delta.Y;
			if (gestureSample.Position.X >= Game1.ScreenWidth/2 && gestureSample.Position.X <= Game1.ScreenWidth)
                        player2Velocity.Y += gestureSample.Delta.Y;
		}
	}
}

 

Овој метод враќа два вредности како што може да се види во првата линија. Во линија 3 ја бришиме цела листа и потоа во while циклус проверуваме дали има некаков инпут преку допир. Доколку има, сите инпути ги додаваме во листата Gestures. Потоа ги иницијализираме векторите на (0,0) и ги проверуваме сите инпути што ги имаме во листата Gestures. Доколку имаме инпут со влечење (FreeDrag), проверуваме на која позиција од екранот се случило влечењето. Доколку се случило во левата половина, брзината од Y оската на влечењето ја додаваме на брзината на играчот во Y оската. Доколку влечењето е во десната половина, истата математика ја правиме за брзината на вториот играч.

Отворете ја Game1.cs класата и најгоре, додадете ја следната библиотека:

using Microsoft.Xna.Framework.Input.Touch;

 

Потоа, сменете го конструкторот во следното:

public Game1()
{
	_graphics = new GraphicsDeviceManager(this);
	Content.RootDirectory = "Content";
	TouchPanel.EnabledGestures = GestureType.FreeDrag;
}

Забележувате ја додадовме 5тата линија. Оваа линија ни дозволува инпут преку влечење на екранот.

Во Update методот, под повикувањето на методите за движење на играчите со тастатура, додадете ги следните линии:

player1.Move(player1Velocity);
player2.Move(player2Velocity);

Vector2 player1TouchVelocity, player2TouchVelocity;
Input.ProcessTouchInput(out player1TouchVelocity, out player2TouchVelocity);
player1.Move(player1TouchVelocity);
player2.Move(player2TouchVelocity);

 

Прво, во линија 4 декларираме два вектори каде што ќе ги чуваме вредностите за брзината на влечење. Откако ќе се повика методот за процесирање на Touch инпутот, повторно ги повикуваме методите за движење.

Како што е покажано на сликата подолу, сменете ја машината за дебагирање од Local Machine во Simulator за да може да го тестирате Touch инпутот.

Притиснете F5 или Debug –> Start Debugging за да го уклучите симулаторот и да го тестирате Touch инпутот.

Колизии

Имаме три работи кои што треба да ги средиме за да го завршиме овој дел. Колизија помеѓу горната и долната страна на екранот и топчето, ограничување на движењето на играчите и колизија помеѓу играчите и топчето.

Прво ќе го средиме топчето. Отворете ја Ball.cs класата и додадете го следниот метод:

public void CheckWallCollision()
{
	if (Position.Y < 0)
	{
		Position.Y = 0;
		Velocity.Y *= -1;
	}
	if (Position.Y + Texture.Height > Game1.ScreenHeight)
	{
		Position.Y = Game1.ScreenHeight - Texture.Height;
		Velocity.Y *= -1;
	}
}

 

Овој метод прво проверува дали топчето излегува од горната страна. Доколку излегува од горната страна, ја сетираме Y координатата на 0 и ја променуваме насоката на брзината (со ова добиваме одбивање од горната страна). Во вториот if-тест се проверува истото за долната страна меѓутоа приметувате дека треба да се искористи и висината на самата текстура бидејќи позицијата се наоѓа на горниот лев агол на самото топче.

Овој метод сега ќе го повикаме во Move методот на топчето. Додадете го следниот метод во Ball.cs класата:

public override void Move(Vector2 amount)
{            
	base.Move(amount);
	CheckWallCollision();
}

 

Овој метод прво го повикува Move методот од GameObject (класата од кој што наследува) и потоа го повикува методот за проверка на колизии со горната и долната страна на екранот.

Пред да тестираме, ќе додадеме неколку линии за да се ресетира топчето доколку излезе од левата или десната страна на екранот.

Отворете ја Game1.cs класата и внесете го следниот код веднаш по процесирањето на Touch инпутот:

player1.Move(player1TouchVelocity);
player2.Move(player2TouchVelocity);

if (ball.Position.X + ball.Texture.Width < 0)
{
	ball.Launch(BALL_START_SPEED);
}

if (ball.Position.X > ScreenWidth)
{
	ball.Launch(BALL_START_SPEED);
}

 

Првиот if-тест проверува дали топчето излегло од левата страна и доколку да, повторно го лансира од центарот на екранот. Вториот if-тест проверува дали топчето излегло од десната страна.

Притиснете F5 или Debug –> Start Debugging за да ги тестирате последните промени. Ќе забележите дека сега топчето се одбива од горната и долната страна, а кога излегува од левата или десната страна се ресетира повторно на центарот на екранот.

Следниот чекор е да се ограничи движењето на играчите. Отворете ја Player.cs класата и додадете ја следната библиотека:

using Microsoft.Xna.Framework;

Потоа, додадете го следниот метод:

public override void Move(Vector2 amount)
{
	base.Move(amount);
	if (Position.Y <= 0)
		Position.Y = 0;
	if (Position.Y + Texture.Height >= Game1.ScreenHeight)
		Position.Y = Game1.ScreenHeight - Texture.Height;
}

 

Како и за топчето, најпрво се повикува Move методот од GameObject (класата од која што наследува) потоа се проверува дали играчот се наоѓа на горната граница  и се ограничува позицијата доколку играчот се обиде да излезе од екранот. Истото се случува и во вториот if-тест каде што се проверува дали играчот сака да излезе од долната страна.

Притиснете F5 или Debug –> Start Debugging и тестирајте ги последните промени. Ќе забележите дека сега играчот не смее да го напушти екранот.

Останува уште последниот дел од колизиите, колизија помеѓу топчето и играчите.

Отворете ја GameObject.cs класата и додадете го следното Property:

public Rectangle Bounds
{
	get { return new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height); }
}

 

Ова Property враќа правоаголник со границите на објектите (играчите и топчето во нашиот случај).

Во истата класа (GameObject.cs) додадете го следниот метод:

public static bool CheckPaddleBallCollision(Player player, Ball ball)
{
	if (player.Bounds.Intersects(ball.Bounds))
		return true;
	return false;
}

 

Овој метод враќа булеан (true или false), а како параметри зема играч и топче. Со користење на Bounds Property-то за добивање на правоаголникот околу објектите се проверува дали правоаголникот на играчот се пресекува со правоаголникот на топчето. Доколку постои пресек, враќаме true. Во спротивост враќаме false.

Овој метод е статичен и може да се повика преку GameObject.CheckPaddleBallCollision(…);

Отворете ја Game1.cs класата и додадете ја следната библиотека:

using System;

 

Потоа во Update методот, веднаш после Touch движењето и пред проверката за повторно лансирање на топчето внесете ги линиите како што е покажано:

player1.Move(player1TouchVelocity);
player2.Move(player2TouchVelocity);

if (GameObject.CheckPaddleBallCollision(player1, ball))
{
	ball.Velocity.X = Math.Abs(ball.Velocity.X);
}

if (GameObject.CheckPaddleBallCollision(player2, ball))
{
	ball.Velocity.X = -Math.Abs(ball.Velocity.X);
}

if (ball.Position.X + ball.Texture.Width < 0)
{
	ball.Launch(BALL_START_SPEED);
}

 

Во четвртата линија забележувате се проверува колизија помеѓу првиот играч и топчето. Доколку постои колизија, брзината на топчето во X оската добива позитивна насока (позитивна насока во случајот значи надесно). Потоа се проверува колизија помеѓу вториот играч и топчето. Доколку постои колизија, се дава негативна вредност на брзината во X оската.

Притиснете F5 или Debug –> Start Debugging за да тестирате.

Со овој чекор го завршуваме третиот дел од овој серијал. Доколку нешто не ви е јасно, или заглавивте некаде, оставете коментар подолу. За да го превземете мојот Solution од овој дел, притиснете тука.

Напомена: Ќе треба да ги сетирате референците до MonoGame за да го тестирате мојот Solution.

Во наредниот, последен дел од овој серијал, ќе ја дотераме играта. Ќе додадеме ‘вртење’ на топчето кога играчот ќе го мава, ќе додадеме индикатори за поени, звуци и слично.

Развивање 2Д Игри За Windows 8 Со MonoGame Втор Дел–Цртање Спрајтови

Како што спомнав на крајот на првиот дел од овој серијал,  во овој дел ќе започнам со развивање на Pong клон. Прво ќе ви објаснам како да ги подготвите екстерните фајлови (слики, спрајтови, звуци итн.), па ќе го креираме проектот каде што ќе ја развиваме играта, ќе ги внесеме компајлираните .xnb фајлови од екстерните фајлови, ќе креираме неколку класи за на крај да ги нацртаме објектите на екран. Без да должам, одиме со првиот чекор.

Подготовка на Екстерни Фајлови

Како што спомнав во првиот дел, Content Pipeline-от за Windows 8 верзијата на MonoGame сеуште не е спремен и затоа ни треба XNA за да ги компајлираме сите надворешни фајлови. Потоа, овие компајлирани фајлови можеме да ги искористиме во нашиот MonoGame проект.

Најпрво превземете го .rar компресираниот фајл наречен Pong Assets од тука. По превземањето, екстрактирајте ги фајловите кои што се внатре во фолдер по ваш избор (пример Desktop). Пуштете го Visual Studio 2012 Express for Windows Phone и креирајте нов Windows Phone Game (4.0) проект. Крстете го PongContent и притиснете ОК.

 

Откако ќе се креира проектот, притиснете десен клик на Content проектот кој што се наоѓа десно Add –> Existing Items…

Навигирајте до фолдерот каде што претходно ги екстрактиравте фајловите, селектирајте ги сите фајлови и притиснете Add за да ги додадете во проектот.

Наредниот чекор е да се компајлира проектот. Притиснете Build –> Build Solution или CTRL+Shift+B на тастатура.

Откако компајлирањето ќе се комплетира, исклучете го Visual Studio 2012 Express for Windows Phone и пуштете Visual Studio 2012 Express for Windows 8.

Креирајте нов проект, изберете MonoGame Game, крстете го PongClone и притиснете OK.

Доколку ги пратевте инструкциите од првиот дел за сетирање на MonoGame преку клонирање на Git репозиторија, сега ќе треба да се повторат чекорите кои што ги напишав под ‘Тестирање на MonoGame’. Тие беа: бришење на постоечките референци, додавање на MonoGame проектот и додавање референца до MonoGame проектот. Доколку не се сеќавате како се правеше тоа, прочитајте ги повторно тука (инструкциите се наоѓаат на крајот – ‘Тестирање на MonoGame’).

Ако го инсталиравте MonoGame преку инсталерот, нема потреба од дополнително сетирање. Со самото креирање на проектот, автоматски се додаваат точните референци до потребните библиотеки.

За секој случај, притиснете F5 или Debug –> Start Debugging за да тестирате дали MonoGame функционира. Доколку ви се појави сина боја, се е во ред и може да продолжиме со наредниот чекор.

Притиснете десен клик на PongClone проектот Add –> New Folder. Крстете го новиот фолдер ‘Content’ (без наводници).

Притиснете десен клик на фолдерот Add –> Existing Item…и навигирајте во:

…\Documents\Visual Studio 2012\Projects\PongContent\PongContent\PongContent\bin\Windows Phone\Debug\Content

Селектирајте ги сите .xnb фајлови и притиснете Add.

 

 

 

 

Следно, селектирајте ги додадените фајлови како што е покажано на сликата лево, под Properties сменете го Build Action од None во Content. (Притиснете на сликата за зум)

 

 

 

 

 

 

Oвој чекор ја комплетира подготовката на екстерните фајлови. Постојат и други начини кои што се малку побрзи (додавање Windows Phone library и Content проект) но за нив потребен е Visual Studio 2012 Professional/Ultimate и се малку покомплексни.

Game Loop

MonoGame ги има истите XNA имиња на namespace-ови, класи, методи итн. Отворете го Game1.cs фајлот каде што е напишан ‘Main’-от на апликацијата. Во истиот фајл, покрај конструкторот, ќе забележите 5 методи: Initialize, LoadContent, UnloadContent, Update и Draw.

Првите два се користат за сетирање на почетните вредности и вчитување на екстерните фајлови. UnloadContent, се користи кога се исклучува апликацијата за да се ослободат вчитаните фајлови. Update и Draw се методите каде што се случуваат чуда! Овие два методи се постојано во еден циклус кој што се нарекува Game Loop и во зависност од платформата може да се сетира брзината во фрејмови во една секунда (FPS).

Во Update се става целата логика (движење, инпут, процесирање на колизии, физика итн.). После сите калкулации се преминува на Draw кој што се користи за цртање на објектите во дадена позиција.

 

GameObject, Player и Ball

За нашиот Pong клон, ќе креираме неколку класи. Во овој дел од серијалот, целта ни е да ги нацртаме објектите на екран. Пред да почнеме со пишување на класите за објектите, ќе напишеме неколку линии за да ги зачуваме димензиите на екранот во секој момент.

Отворете го Game1.cs фајлот доколку претходно не го отворивте и под веќе напишаните линии за _graphics и _spriteBatch додадете две статични int променливи каде што ќе се чува ширината и висината на екранот.

        
GraphicsDeviceManager _graphics;
SpriteBatch _spriteBatch;

public static int ScreenWidth;
public static int ScreenHeight;

 

Малку подолу, во методот Initialize, иницијализирајте ги двете променливи:

ScreenWidth = GraphicsDevice.Viewport.Width;
ScreenHeight = GraphicsDevice.Viewport.Height;

base.Initialize();

 

Сега, во Update методот додадете ги истите две линии.

ScreenWidth = GraphicsDevice.Viewport.Width;
ScreenHeight = GraphicsDevice.Viewport.Height;

base.Update(gameTime);

 

Со овие линии, ќе ги имаме димензиите на екранот во секој момент, кога и да се сменат (пример Snap View во Windows 8).

Сега може да ги креираме класите за објектите кои што ќе ги користиме во играта. Бидејќи играчите и топчето имаат неколку заеднички атрибути, ќе креираме една супер класа наречена GameObject и од таа класа ќе има наследување за Player и Ball.

Притиснете десен клик на PongClone проектот и додадете нов фолдер ‘Classes’ (без наводници). Притиснете десен клик на ‘Classes’ фолдерот, Add –> Class…

Крстете ја класата GameObject и притиснете Add.

Повторете го истото за да ги додадете класите за Player и Ball.

Отворете ја GameObject класата и преправете ја во следното:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace PongClone
{
    public class GameObject
    {
        public Vector2 Position;
        public Texture2D Texture;
    }
}

 

Ќе забележите во линиите 6 и 7 додадени се две библиотеки кои што ги содржат Vector2 и Texture2D класите искористени во линиите 13 и 14. Исто така во линија 9 избришан е .Classes за да можеме да пристапиме до GameObject класата без да пишуваме Classes.GameObject.

Во линија 11 додаден е зборот public за да може да пристапиме до класата од други класи. Во линија 13, деклариран е дво-димензионален вектор за позиција кој што содржи X и Y координата. Во линија 14, декларирана е променлива за да се зачува текстурата на објектот.

Напомена: Во нашата игра ќе избегнувам користење на private, protected итн. зборови поради едноставност.

Нареден чекор е да се додаде метод за цртање. Додадете го следниот метод:

public void Draw(SpriteBatch spriteBatch)
{
	spriteBatch.Draw(Texture, Position, Color.White);
}

 

Со овој метод се користи SpriteBatch објект за цртање на 2Д објекти на екран. spriteBatch.Draw(…) методот има неколку overload-и, јас ќе го искористам четвртиот каде што се користат Texture2D, Vector2 и Color параметри. Оваа линија ја црта дадената текстура Texture во дадена позиција Position. Последниот параметар се користи за менување на бојата на текстурата. Color.White се користи за зачувување на оригиналната боја на самата текстура.

Отворете ја Player.cs класата и преправете ја во следното:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PongClone
{
    public class Player : GameObject
    {
    }
}

 

Во линија 7 избришан е .Classes. Во линија 9, додаден е зборот public и : GameObject за да се означи наследување од GameObject.

Отворете ја Ball.cs класата и преправете ја во следното:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PongClone
{
    public class Ball : GameObject
    {
    }
}

 

Исто и тука, направени се истите промени.

Цртање на Играчите и Топчето

Отворете ја Game1.cs класата и креирајте променливи за играчите и топчето. Исто така ќе креираме и една int константа за офсет на играчите од десниот и левиот крај на екранот:

const int PADDLE_OFFSET = 70;

Player player1;
Player player2;
Ball ball;

 

Бројката 70 ќе ни претставува 70 пиксели офсет од левата и десната страна на екранот.

Преправете го Initialize методот во следното:

protected override void Initialize()
{
	// TODO: Add your initialization logic here

	ScreenWidth = GraphicsDevice.Viewport.Width;
	ScreenHeight = GraphicsDevice.Viewport.Height;

	player1 = new Player();
	player2 = new Player();
	ball = new Ball();
            
	base.Initialize();
}

Во линиите 8,9 и 10 се креираат објектите за играчите и топчето. Следно, ќе треба да се вчитаат текстурите и да се сетираат почетните позиции на трите објекти.

Преправете го LoadContent во следното:

protected override void LoadContent()
{
	// Create a new SpriteBatch, which can be used to draw textures.
	_spriteBatch = new SpriteBatch(GraphicsDevice);

	// TODO: use this.Content to load your game content here
	player1.Texture = Content.Load<Texture2D>("Paddle");
	player2.Texture = Content.Load<Texture2D>("Paddle");

	player1.Position = new Vector2(PADDLE_OFFSET, ScreenHeight / 2 - player1.Texture.Height / 2);
	player2.Position = new Vector2(ScreenWidth - player2.Texture.Width - PADDLE_OFFSET, ScreenHeight / 2 - player2.Texture.Height / 2);

	ball.Texture = Content.Load<Texture2D>("Ball");
	ball.Position = new Vector2(ScreenWidth / 2 - ball.Texture.Width / 2, ScreenHeight / 2 - ball.Texture.Height / 2);
}

 

Во линиите 7 и 8 ја вчитуваме истата текстура за двајцата играчи. Текстурата ни се наоѓа во Content фолдерот. Потоа ги сетираме позициите на играчите. Во 10тата линија, за X координатата го користиме офсет-от од 70 пиксели. За Y координатата ја земаме во предвид висината на екранот и висината на текстурата на играчот за точно да се постави на средина.

Во 11тата линија се зема во предвид целата ширина на екранот за да се постави вториот играч на десната страна.

Во линиите 13 и 14, се вчитува текстурата за топчето и се сетира позицијата на топчето.

Напомена: (0,0) на екранот се наоѓа на горниот лев агол. Слика тука.

Конечно стигнавме до последниот дел, цртање на објектите. Преправете го Draw методот во следното:

protected override void Draw(GameTime gameTime)
{
	GraphicsDevice.Clear(Color.Black);

	// TODO: Add your drawing code here
	_spriteBatch.Begin();
	player1.Draw(_spriteBatch);
	player2.Draw(_spriteBatch);
	ball.Draw(_spriteBatch);
	_spriteBatch.End();
	base.Draw(gameTime);
}

 

Во третата линија, смената е бојата на позадината од CornflowerBlue во Black. Потоа за да се започне со цртање, се користи методот _spriteBatch.Begin() . Во линиите 7, 8 и 9 го користиме методот кој што го напишавме во GameObject класата за да ги нацртаме елементите. Откако се завршува со цртање, се прекинува SpriteBatch објектот со _spriteBatch.End().

Притиснете F5 или Debug –> Start Debugging. Доколку немате некакви синтаксички грешки би требало да го гледате ова:

Целосниот Solution на овој дел, може да го спуштете од тука.

Напомена: Ќе треба да ги сетирате референците до MonoGame за да го тестирате мојот Solution.

Доколку имате некакви проблеми, оставете коментар подолу.

Во третиот дел, ќе ставиме инпут, движење и колизии.

Развивање 2Д Игри За Windows 8 Со MonoGame Прв Дел – Подготовка

Овој серијал ќе се состои од неколку делови за тоа како може да се развие една 2Д игра на Windows 8.

Прв Дел – Подготовка

Втор Дел – Цртање Спрајтови

Трет Дел – Логика На Игра

Четврт Дел – Дотерување

Со XNA многу лесно и брзо може да се развијат мали игри или прототипи, а исто така може да се развијат и посериозни игри како Fez, Terraria, Bastion итн. За жал, Microsoft одлучија да не го продолжат развивањето на XNA Framework-от, и игрите креирани со него не може да се објават на Windows Store. Од друга страна, обичните десктоп апликации функционираат без проблеми. Поради тоа, морав да побарам некаква алтернатива.

MonoGame е еден од поразвиените open source проекти кои што го имплементираат XNA Framework-от за лесно портирање на XNA апликации на други платформи (Mac, Android итн), но исто така може да се користи за развивање нови игри. Благодарение на Том Спилман и Џејмс Форд од SickHeadGames и уште неколку други талентирани девелопери, MonoGame сега го подржува и Windows 8. Апликациите кои што се креираат со MonoGame може да се објават на Windows Store. Во овој серијал, со помош на MonoGame планирам да ви покажам како може да се креира Pong, кој што се смета за “Hello World!” во Game Development 🙂

Другите алтернативи за креирање игри кои може да се користат со цел објавување на Windows Store се користење HTML5/JavaScript или DirectX.

             

Подготовка на Системот

Пред да преминеме на сетирање на MonoGame, потребен е следниот софтвер (пожелно е да се инсталира во овој редослед):

  1. Windows 8 (Release Preview може да се спушти бесплатно тука)

Сигурно се прашувате зошто ви треба Visual Studio 2012 for Windows Phone. Во XNA постои Content Pipeline кој што се користи пред компајлирање за да се подготват графичките податоци (слики, спрајтови, модели итн.), звучните податоци (звуци, музика) и други екстерни податоци. Content Pipeline-от сеуште не е интегриран во Windows 8 верзијата на MonoGame, па затоа ќе треба да ги компајлирате екстерните податоци во Visual Studio 2012 for Windows Phone (кој што подржува XNA проект) и потоа да ги копирате во вашиот Visual Studio 2012 for Windows 8 проект. Повеќе за ова во еден од наредните делови на овој серијал.

Доколку имате Visual Studio 2012 Professional или Ultimate, ќе треба да го инсталирате Windows Phone 8.0 SDK за да можете да креирате XNA Windows Phone проект.

Во случај да имате некакви проблеми, оставете коментар подолу.

Подготовка на MonoGame

Постојат два начини на кој што може да се инсталира MonoGame. Првиот е преку обичен installer од тука. А вториот (кој што ќе го објаснам тука) е преку Git репозиторија. Зошто вториот? Затоа што инсталерот ретко се update-ира, додека во Git репозиторијата секојдневно се поправаат различни багови и се додават нови feature-и.

За овој дел потребен ви е некаков Git client. Јас го користам TortoiseGit бидејќи е доста едноставен. Доколку сакате можете да користите друг клиент.

  1. Спуштете и инсталирајте TortoiseGit.
  2. Спуштете и инсталирајте Git.

По комплетирањето на инсталациите треба да се клонира кодот на MonoGame. За да го направите тоа најпрво навигирајте во некој фолдер по ваш избор каде што ќе ги спуштите сите потребни податоци. Јас ќе направам клон на мојот десктоп.

Забелешка: Комплетниот клон вклучува StarterKit-ови и Sample проекти па затоа е голем околу 1.6GB.

Притиснете десен клик на празно место на десктоп, потоа притиснете на Git Clone…

Ставете ја следната адреса во URL полето: https://github.com/mono/MonoGame

Чекирајте го Recursive полето и притиснете OK.

Сега ќе треба да почекате некое време додека не заврши процесот на клонирање. Како што напоменав погоре, клонот е околу 1.6GB.

Креирање и Имплементација на MonoGame Template во Visual Studio 2012

Откако ќе заврши процесот на клонирање:

  1. Отворете го MonoGame фолдерот и навигирајте во ProjectTemplates\VisualStudio2012\Game
  2. Креирајте ZIP од сите датотеки во фолдерот.
  3. Копирајте ја ZIP датотеката во Visual Studio 2012 Visual C# Templates директоријата.

    C:\Users\Корисничко име\Documents\Visual Studio 2012\Templates\ProjectTemplates\Visual C#

  4. Бонус: Доколку го сакате и XAML темплејтот направете го истото за датотеките во MonoGame\ProjectTemplates\VisualStudio2012\XamlGame

Тестирање на MonoGame

  1. Пуштете го Visual Studio 2012 for Windows 8 (или Visual Studio 2012 ако имате Pro или Ultimate верзија) и креирајте нов проект.
  2. Под Visual C# сега треба да имате MonoGame темплејт(и). Одберете го Game темплејтот и притиснете ОК.
  3. Бидејќи темплејтот е истиот од инсталерот, референците до библиотеките имаат погрешен Path. Селектирајте ги сите референци како на сликата подолу и избришете ги:
  4. Притиснете десен клик на Solution –> Add –> Existing Project.
  5. Навигирајте во MonoGame\MonoGame.Framework и додадете го MonoGame.Framework.Windows8.csproj проектот.
  6. Сега треба да додадете Reference во вашиот проект до MonoGame проектот. Притиснете десен клик на References –> Add Reference…
  7. На левата страна одберете Solution –> Project и чекирајте го полето како на сликата подолу. Потоа притиснете ОК.
  8. Притиснете F5 за да компајлирате и да ја лансирате апликацијата. Ако ви се појави сина боја, процесот е успешен.

Доколку имате некакви проблеми, оставете коментар подолу.

Во наредниот дел, ќе започнеме со развивањето на Pong.