Сегодня начнем знакомиться с 2d физическим движком, который можно использовать в XNA. http://farseerphysics.codeplex.com . Движок бесплатный, разработка новых версий ведется. Использую версию 2.1.3 (c# 2008 express, XNA 3.1)
Для начала я приведу самый простой код чтобы быстро понять базис и сделать «привет миру».
Создаем проект из шаблона winGame, подключаем библиотеку, которую нужно скачать на сайте разработчика (взять готовую или взять проект и скомпилировать у себя).
Подключил в общие ссылки, потому что хотела XNA 3.0, а у меня 3.1. Но это не страшно, потому что мы только знакомимся, - ошибку можно исправить методами студии и с выходом новой версии для полноценного релиза игры.
Задумка такая: есть 2 объекта один из них статичен, а второй динамичный и управляется нами: Коробка, на столе. Управляем коробкой, а не столом :)
Первое что нам нужно это добавить пространства имен в проект:
В конструкторе класса создаем физический симулятор, и задаем ему направление гравитации:
Для начала я приведу самый простой код чтобы быстро понять базис и сделать «привет миру».
Создаем проект из шаблона winGame, подключаем библиотеку, которую нужно скачать на сайте разработчика (взять готовую или взять проект и скомпилировать у себя).
Подключил в общие ссылки, потому что хотела XNA 3.0, а у меня 3.1. Но это не страшно, потому что мы только знакомимся, - ошибку можно исправить методами студии и с выходом новой версии для полноценного релиза игры.
Задумка такая: есть 2 объекта один из них статичен, а второй динамичный и управляется нами: Коробка, на столе. Управляем коробкой, а не столом :)
Первое что нам нужно это добавить пространства имен в проект:
using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories;В свойства основного класса добавляем:
PhysicsSimulator physicsSimulator; Body boxBody; Geom boxGeom; float boxMass=0.1f; float boxWidth = 100; float boxHeight = 100; Texture2D boxTexture; Body platformBody; Geom platformGeom; float platformWidth = 1000; float platformHeight = 100; Texture2D platformTexture;Опишу то что ново PhysicsSimulator это главный класс самого симулятора – без него никак именно сюда все складывается обрабатывается и обновляется. Каждый объект движка должен иметь два класса: свойства самого тела (Body) – вес, инерция, направление силы и т.д.; и его геометрию Geom (координатные характеристики) – для расчета коллизий и взаимодействий с другими объектами.
В конструкторе класса создаем физический симулятор, и задаем ему направление гравитации:
physicsSimulator = new PhysicsSimulator(new Vector2(0, 100));А в методе обновления добавим обновление симулятора
physicsSimulator.Update(gameTime.ElapsedGameTime.Milliseconds * 0.001f);Теперь перейдем к методу загрузки данных (контента):
boxBody = BodyFactory.Instance.CreateRectangleBody(physicsSimulator, boxWidth, boxHeight, boxMass); boxBody.Position = new Vector2(700, 100); boxGeom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, boxBody, boxWidth, boxHeight); boxTexture = new Texture2D(GraphicsDevice, (int)boxWidth, (int)boxHeight, 1, TextureUsage.None, SurfaceFormat.Color); Color[] color = new Color[(int)boxWidth * (int)boxHeight]; for (int i = 0; i < color.Length; i++) color[i] = Color.Red; boxTexture.SetData(color); platformBody = BodyFactory.Instance.CreateRectangleBody(physicsSimulator, platformWidth, platformHeight, 1); platformGeom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, platformBody, platformWidth, platformHeight); platformBody.Position = new Vector2(1280/2,720/2); platformBody.IsStatic = true; platformTexture = new Texture2D(GraphicsDevice, (int)platformWidth, (int)platformHeight, 1, TextureUsage.None, SurfaceFormat.Color); Color[] bcolor = new Color[(int)platformWidth * (int)platformHeight]; for (int i = 0; i < bcolor.Length; i++) bcolor[i] = Color.Green; platformTexture.SetData(bcolor);С помощью BodyFactory создаем тело с параметрами ширина, высота, масса. Задаем ему начальную позицию. Далее создаем этому телу геометрию, опять же с помощью фабрики, но уже GeomFactory, передаем тело, ширину, высоту. То же самое производим с телом платформой (столом) только после всех действий указываем, что оно статично: platformBody.IsStatic = true. Текстуры я не готовил специально – потому, что так код становиться более универсальный, и самое главное, что так виднее узреть само взаимодействие. Для создания монотонной текстуры средствами кода я использовал:
boxTexture = new Texture2D(GraphicsDevice, (int)boxWidth, (int)boxHeight, 1, TextureUsage.None, SurfaceFormat.Color); Color[] color = new Color[(int)boxWidth * (int)boxHeight]; for (int i = 0; i < color.Length; i++) color[i] = Color.Red; boxTexture.SetData(color);Тут нечего описывать: создается пустая текстура и попиксельно собираться цвет для ее закрашивания. Чтобы управлять объектом - добавляем код в метод обновления:
if (keyboardState.IsKeyDown(Keys.Up)) boxBody.ApplyForce(new Vector2(0, -100)); if (keyboardState.IsKeyDown(Keys.Down)) boxBody.ApplyForce(new Vector2(0, 100)); if (keyboardState.IsKeyDown(Keys.Left)) boxBody.ApplyForce(new Vector2(-100, 0)); if (keyboardState.IsKeyDown(Keys.Right)) boxBody.ApplyForce(new Vector2(100, 0));В соответствии одной из четырех клавиш (вверх, вниз, влево, вправо) применяем вектор силы методом ApplyForce. Часто нужно остановить тело внезапно, я не нашел встроенного метода чтобы реализовать это нужно использовать такую формулу (по нажатию на пробел тело останавливается, но не перестает крутиться):
if (keyboardState.IsKeyDown(Keys.Space)) boxBody.ApplyImpulse(boxBody.LinearVelocity * -boxBody.Mass);Полный текст кода
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Interfaces;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Factories;
namespace FarseerEx1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
PhysicsSimulator physicsSimulator;
Body boxBody;
Geom boxGeom;
float boxMass=0.1f;
float boxWidth = 100;
float boxHeight = 100;
Texture2D boxTexture;
Body platformBody;
Geom platformGeom;
float platformWidth = 1000;
float platformHeight = 100;
Texture2D platformTexture;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
physicsSimulator = new PhysicsSimulator(new Vector2(0, 100));
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
boxBody = BodyFactory.Instance.CreateRectangleBody(physicsSimulator, boxWidth, boxHeight, boxMass);
boxBody.Position = new Vector2(700, 100);
boxGeom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, boxBody, boxWidth, boxHeight);
boxTexture = new Texture2D(GraphicsDevice, (int)boxWidth, (int)boxHeight, 1, TextureUsage.None, SurfaceFormat.Color);
Color[] color = new Color[(int)boxWidth * (int)boxHeight]; for (int i = 0; i < color.Length; i++) color[i] = Color.Red;
boxTexture.SetData(color);
platformBody = BodyFactory.Instance.CreateRectangleBody(physicsSimulator, platformWidth, platformHeight, 1);
platformGeom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, platformBody, platformWidth, platformHeight);
platformBody.Position = new Vector2(1280/2,720/2);
platformBody.IsStatic = true;
platformTexture = new Texture2D(GraphicsDevice, (int)platformWidth, (int)platformHeight, 1, TextureUsage.None, SurfaceFormat.Color);
Color[] bcolor = new Color[(int)platformWidth * (int)platformHeight]; for (int i = 0; i < bcolor.Length; i++) bcolor[i] = Color.Green;
platformTexture.SetData(bcolor);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
KeyboardState keyboardState=Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Up)) boxBody.ApplyForce(new Vector2(0, -100));
if (keyboardState.IsKeyDown(Keys.Down)) boxBody.ApplyForce(new Vector2(0, 100));
if (keyboardState.IsKeyDown(Keys.Left)) boxBody.ApplyForce(new Vector2(-100, 0));
if (keyboardState.IsKeyDown(Keys.Right)) boxBody.ApplyForce(new Vector2(100, 0));
if (keyboardState.IsKeyDown(Keys.Space)) boxBody.ApplyImpulse(boxBody.LinearVelocity * -boxBody.Mass);
physicsSimulator.Update(gameTime.ElapsedGameTime.Milliseconds * 0.001f);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(boxTexture, boxBody.Position, null, Color.White, boxBody.Rotation, new Vector2(boxTexture.Width / 2, boxTexture.Height / 2), 1, SpriteEffects.None, 0);
spriteBatch.Draw(platformTexture, platformBody.Position, null, Color.White, platformBody.Rotation, new Vector2(platformTexture.Width / 2, platformTexture.Height / 2), 1, SpriteEffects.None, 0);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Файл проект FarseerEx1.zip


Комментарии
Отправить комментарий