I have created a MonoGame iOS solution in Xamarin Studio. After that, I added Farseer Physics Engine to my solution. My project is a simple GameState management. I try to load and unload stuff. Everything seems to work, except creating a Farseer CompoundPolygon. After creating a Farseer CompoundPolygon, the Farseer Debug View is no more drawing the Farseer shapes. In addition, sprites(for example the file Settingsbackground) are not drawn on the screen. I get no error messages and the game is not freezing, it still runs(I checked it with breakpoints), but nothing from the Settings class gets drawn after creating a Farseer CompoundPolygon. There must be a problem with Farseer CompoundPolygon, because everything works if I don’t create a CompoundPolygon.
What is wrong with my project? Is this a bug in the Farseer Physics Engine or am I doing something wrong?
Should I change the way I load/unload content?
I have uploaded my project here: Dropbox - File Deleted - Simplify your life
In this picture, drawing is not working correctly because I’m already in the Settings GameState and I have created a Farseer CompoundPolygon. But the file Settingsbackground and the Farseer Debug View are not drawn.
Game1.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.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Common.PolygonManipulation;
using FarseerPhysics.DebugView;
namespace iPhoneGamestates
{
public class Game1 : Game
{
GraphicsDevice graphicsdevice;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Body Polygon; public float PolygonScale; public Vector2 PolygonOrigin; public List<Vertices> Polygonlist = new List<Vertices>(); public Texture2D PolygonSprite;
public Camera camera; public Vector2 vp, gameWorldSize = new Vector2(1334, 750); public float ScaleX, ScaleY, Scale; Vector2 Newcameraposition;
public bool Draw_debugView = false; public DebugViewXNA physicsDebug; public World world; public Body Ball; public Texture2D BallSprite; public bool UpdateFarseerWorld = false;
public Texture2D Menubackground, Introbackground, Settingsbackground; public float delta; public bool NextGameState = false, Settingscreenactivated = false; IState lastState, currentState, savelastState;
public ContentManager SettingsContent; public ContentManager IntroContent; public ContentManager MenuContent;
public enum GameStates { IntroState = 0, MenuState = 1, SettingsState = 2 }
public void ChangeGameState(GameStates newState) { if (newState == currentGameState) return; lastGameState = currentGameState; lastState = currentState; switch (newState) { case GameStates.IntroState: currentState = new Intro(this, GraphicsDevice); currentGameState = GameStates.IntroState; break; case GameStates.MenuState: currentState = new Menu(this, GraphicsDevice); currentGameState = GameStates.MenuState; if (IntroContent != null) IntroContent.Unload(); if (SettingsContent != null) SettingsContent.Unload(); break; case GameStates.SettingsState: currentState = new Settings(this, GraphicsDevice); currentGameState = GameStates.SettingsState; break;
} currentState.Load(Content); }
public void ChangeToLastandCurrent() { savelastGameState = currentGameState; currentGameState = lastGameState; lastGameState = savelastGameState; savelastState = currentState; currentState = lastState; lastState = savelastState; }
public GameStates CurrentState { get { return currentGameState; } set { currentGameState = value; } }
public GameStates LastState { get { return lastGameState; } set { lastGameState = value; } }
private GameStates currentGameState; private GameStates lastGameState; private GameStates savelastGameState;
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.IsFullScreen = true; }
protected override void Initialize() { currentState = new Intro(this, graphicsdevice); currentGameState = GameStates.IntroState;
base.Initialize(); }
protected override void UnloadContent() { Content.Unload(); }
public void IntroLoad() { Introbackground = IntroContent.Load<Texture2D>("Content/Introbackground"); }
public void SettingsLoad() { Settingsbackground = SettingsContent.Load<Texture2D>("Content/Settingsbackground");
if (world == null) { world = new World(new Vector2(0, 7)); } else { world.Clear(); world = new World(new Vector2(0, 7)); } UpdateFarseerWorld = true;
physicsDebug = new DebugViewXNA(world); physicsDebug.DefaultShapeColor = Color.White; physicsDebug.SleepingShapeColor = Color.LightGray; physicsDebug.LoadContent(GraphicsDevice, Content);
Draw_debugView = true;
BallSprite = SettingsContent.Load<Texture2D>("Content/Ball");
Ball = BodyFactory.CreateCircle(world, 0.25f, 1.0f); Ball.BodyType = BodyType.Static; Ball.Position = new Vector2(6.4f, 3f); Ball.IsSensor = false; Ball.Restitution = 0.4f; Ball.CollisionCategories = Category.Cat30;
PolygonSprite = SettingsContent.Load<Texture2D>("Content/Ground");
uint[] polygondata = new uint[PolygonSprite.Width * PolygonSprite.Height]; PolygonSprite.GetData(polygondata); Vertices polygontextureVertices = PolygonTools.CreatePolygon(polygondata, PolygonSprite.Width, false); Vector2 polygoncentroid = -polygontextureVertices.GetCentroid(); polygontextureVertices.Translate(ref polygoncentroid); PolygonOrigin = -polygoncentroid; polygontextureVertices = SimplifyTools.ReduceByDistance(polygontextureVertices, 4f); Polygonlist = Triangulate.ConvexPartition(polygontextureVertices, TriangulationAlgorithm.Bayazit); PolygonScale = 1f; Vector2 polygonvertScale = new Vector2(ConvertUnits.ToSimUnits(1)) * PolygonScale; foreach (Vertices polygonvertices in Polygonlist) { polygonvertices.Scale(ref polygonvertScale); }
Polygon = BodyFactory.CreateCompoundPolygon(world, Polygonlist, 1.0f, BodyType.Dynamic); Polygon.BodyType = BodyType.Static; Polygon.IsSensor = false; Polygon.Position = new Vector2(6f, 4.5f); Polygon.Rotation = 0f; Polygon.Restitution = 0.05f; Polygon.CollisionCategories = Category.Cat25; }
public void MenuLoad() { Menubackground = MenuContent.Load<Texture2D>("Content/Menubackground"); }
protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); vp = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
ScaleX = vp.X / gameWorldSize.X; ScaleY = vp.Y / gameWorldSize.Y; Scale = Math.Min(ScaleX, ScaleY);
camera = new Camera(new Vector2(gameWorldSize.X / 2, gameWorldSize.Y / 2), Scale, vp);
currentState.Load(Content);
TouchPanel.EnabledGestures = GestureType.Tap; }
protected override void Update(GameTime gameTime) { delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
if ((UpdateFarseerWorld == true) && (world != null)) world.Step(Math.Min(delta, (1f / 60f)));
Newcameraposition = new Vector2(gameWorldSize.X / 2, gameWorldSize.Y / 2);
camera.Update(gameTime, Newcameraposition, Scale, vp);
while (TouchPanel.IsGestureAvailable) { GestureSample gs = TouchPanel.ReadGesture(); switch (gs.GestureType) { case GestureType.Tap: NextGameState = true; break; } }
if ((lastGameState == GameStates.MenuState) && (currentGameState == GameStates.SettingsState)) { lastState.Update(gameTime); }
currentState.Update(gameTime);
base.Update(gameTime); }
protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, camera.GetMatrix()); if ((lastGameState == GameStates.MenuState) && (currentGameState == GameStates.SettingsState)) { lastState.Render(spriteBatch); }
currentState.Render(spriteBatch); spriteBatch.End();
if (Draw_debugView == true) { float zoom = Scale; float width = (1f / zoom) * ConvertUnits.ToSimUnits(GraphicsDevice.Viewport.Width); float height = (-1f / zoom) * ConvertUnits.ToSimUnits(GraphicsDevice.Viewport.Height); float zNearPlane = 0f; float zFarPlane = 1000000f; Matrix projection = Matrix.CreateOrthographic(width, height, zNearPlane, zFarPlane);
float xTranslation = -1 * ConvertUnits.ToSimUnits(camera.PlayerPosition.X); float yTranslation = -1 * ConvertUnits.ToSimUnits(camera.PlayerPosition.Y); Vector3 translationVector = new Vector3(xTranslation, yTranslation, 0f); Matrix view = Matrix.Identity; view.Translation = translationVector;
physicsDebug.RenderDebugData(ref projection, ref view); }
base.Draw(gameTime); }
}
}
Intro.cs:
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.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
namespace iPhoneGamestates
{
public class Intro : IState
{
private Game1 game1;
GraphicsDevice graphicsDevice;
float Count = 5f;
bool ChangeGameState = true;
public Intro(Game1 game, GraphicsDevice device) { game1 = game; graphicsDevice = device; game1.IntroContent = new ContentManager(game1.Services); }
public void Load(ContentManager content) { game1.IntroLoad(); }
public void Update(GameTime gametime) { Count -= game1.delta; if ((Count < 0) && (ChangeGameState == true)) { ChangeGameState = false; game1.ChangeGameState(Game1.GameStates.MenuState); } } public void Render(SpriteBatch batch) { batch.Draw(game1.Introbackground, new Rectangle((int)game1.gameWorldSize.X / 2, (int)game1.gameWorldSize.Y / 2, game1.Introbackground.Width, game1.Introbackground.Height), null, Color.White, 0, new Vector2(game1.Introbackground.Width / 2, game1.Introbackground.Height / 2), SpriteEffects.None, 0.10f); }
}
}
Menu.cs:
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.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.Common;
using FarseerPhysics.DebugView;
namespace iPhoneGamestates
{
public class Menu : IState
{
private Game1 game1;
GraphicsDevice graphicsDevice;
public Menu(Game1 game, GraphicsDevice device) { game1 = game; graphicsDevice = device; game1.MenuContent = new ContentManager(game1.Services); }
public void Load(ContentManager content) { game1.MenuLoad(); }
public void Update(GameTime gametime) { if ((game1.NextGameState == true) && (game1.Settingscreenactivated == false)) { game1.NextGameState = false; game1.Settingscreenactivated = true; game1.ChangeGameState(Game1.GameStates.SettingsState); } }
public void Render(SpriteBatch batch) { batch.Draw(game1.Menubackground, new Rectangle((int)game1.gameWorldSize.X / 2, (int)game1.gameWorldSize.Y / 2, game1.Menubackground.Width, game1.Menubackground.Height), null, Color.White, 0, new Vector2(game1.Menubackground.Width / 2, game1.Menubackground.Height / 2), SpriteEffects.None, 0.10f); }
}
}
Settings.cs:
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.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.Common;
namespace iPhoneGamestates
{
public class Settings : IState
{
private Game1 game1;
GraphicsDevice graphicsDevice;
public Settings(Game1 game, GraphicsDevice device) { game1 = game; graphicsDevice = device; game1.SettingsContent = new ContentManager(game1.Services); }
public void Load(ContentManager content) { game1.SettingsLoad(); }
public void Update(GameTime gametime) { if (game1.NextGameState == true) { game1.NextGameState = false; game1.UpdateFarseerWorld = false; game1.Draw_debugView = false; game1.Settingscreenactivated = false; game1.ChangeGameState(Game1.GameStates.MenuState); }
}
public void Render(SpriteBatch batch) { batch.Draw(game1.Settingsbackground, new Rectangle((int)game1.gameWorldSize.X / 2, (int)game1.gameWorldSize.Y / 2, game1.Settingsbackground.Width, game1.Settingsbackground.Height), null, Color.White, 0, new Vector2(game1.Settingsbackground.Width / 2, game1.Settingsbackground.Height / 2), SpriteEffects.None, 0.09f);
batch.Draw(game1.PolygonSprite, ConvertUnits.ToDisplayUnits(game1.Polygon.Position), null, Color.White, game1.Polygon.Rotation, new Vector2(game1.PolygonSprite.Width / 2.0f, game1.PolygonSprite.Height / 2.0f), game1.PolygonScale, SpriteEffects.None, 0.05f);
batch.Draw(game1.BallSprite, ConvertUnits.ToDisplayUnits(game1.Ball.Position), null, Color.White, game1.Ball.Rotation, new Vector2(game1.BallSprite.Width / 2.0f, game1.BallSprite.Height / 2.0f), 1f, SpriteEffects.None, 0.04f); }
}
}