I have a function for raycasting on a grid with Bresenham's algorithm. I want to optimize for specific cases when the line is orthogonal or diagonal; of course, this logic won't be returned/exposed to the user.
Is it possible to detect the optimization edge case throught a unit test? E.g. Look for a specific Debug.WriteLine marker when calling the function.
I'm new to unit testing and I might be missing the point (testing functionality exposed to the user) but asserting that my edge cases work as expected can be invaluable - especially when actively developing the optimizations.
Example of what I want to achieve:
public IEnumerable<Coordinate> RayCast (Coordinate source, Coordinate direction) {
if (direction.X == 0 || direction.Y == 0) {
Debug.WriteLine ("Orthogonal_Edge_Case");
//Simple iteration across 1 axis
...
yield break;
}
if (Math.Abs(direction.X) == Math.Abs(direction.Y)) {
Debug.WriteLine ("Diagonal_Edge_Case");
//Simple diagonal iteration
...
yield break;
}
//Standard Bresenham's algorithm
...
yield break;
}
...
[TestMethod]
public void TestRayCast () {
var source = new Coordinate (0,0);
var orthogonal = new Coordinate (0,1);
CoordinateUtil.RayCast (source, orthogonal);
//Check that the Orthogonal_Edge_Case marker was emitted
var diagonal = new Coordinate (1,1);
CoordinateUtil.RayCast (source, diagonal);
//Check that the Diagonal_Edge_Case marker was emitted
//Usual tests for RayCast
...
}
Note: I'm using Visual Studio 2019's unit test kit but I'm curious if this is possible with any .NET tool
You have a couple of options:
Hold some sort of state using a property in CoordinateUtil which will allow you to check what was the last edge detected. This will however break the Command Query Responsibility Segregation pattern.
Inject an edge case detector (which you can easily mock with mocking framework). The example below use Moq.
Inject an ILogger which will allow you to log some timing information amongst other things (very similar to option2 but with slightly different set up).
Below shows how option 2 works. You may feel it is overkill but it is robust and how things are generally done in large projects. Also note that you are now exposing internals to the outside world, just to help with internal optimisation. If so then this may not be appropriate.
public class CoordinateUtil
{
private readonly IEdgeCaseDetector edgeCaseDetector;
// This is the important bit where you inject an edge case detector
public CoordinateUtil(IEdgeCaseDetector edgeCaseDetector)
{
this.edgeCaseDetector = edgeCaseDetector;
}
public IEnumerable<Coordinate> RayCast(Coordinate source, Coordinate direction)
{
if (direction.X == 0 || direction.Y == 0)
{
edgeCaseDetector.Detect("Orthogonal_Edge_Case");
//Simple iteration across 1 axis
yield break;
}
if (Math.Abs(direction.X) == Math.Abs(direction.Y))
{
edgeCaseDetector.Detect("Diagonal_Edge_Case");
//Simple diagonal iteration
yield break;
}
//Standard Bresenham's algorithm
yield break;
}
}
public interface IEdgeCaseDetector
{
void Detect(string message);
}
public class EdgeCaseDetector
{
public void Detect(string message)
{
// If you wanted to you could simply save the edge cases to a public property here
// Or you might want to log them when you code runs outside of the unit test
}
}
[TestClass]
public class CoordinateUtilTests
{
[TestMethod]
public void RayCast_WhenOthogonal_DetectsEdgeCase()
{
// Arrange
var mock = new Mock<IEdgeCaseDetector>();
var coordinateUtil = new CoordinateUtil(mock.Object);
var source = new Coordinate(1, 1);
// Act
// Remember the ToArray because we need to evaluate the enumerable
// before we can check if the edge case was detected.
coordinateUtil.RayCast(source, new Coordinate(0, 0)).ToArray();
// Assert
mock.Verify(x => x.EdgeDetected("Orthogonal_Edge_Case"));
}
}
Exposing internal logic to the external world only for sake of the tests, wouldn't be best approach.
You should test only against public api and behaviour.
For performance tests it can be tricky, but doable. For example what behaviour consumer of the method under the test will observe if you execute Standard Bresenham's algorithm for edge cases?
Does execution will takes more then 500 milliseconds? If so, write test for it and check that for edge cases execution takes less then 500 milliseconds.
If you can not find such observable behaviour I would not write tests for it, and just trust developer who ever write or maintain this code. All developers smart people and try their best.
Related
I'm making a game, in which I have various fields that I'd like to set target values for. For example, my Camera class has:
public double zoomLevel
Currently, if the zoomLevel is (say) 1.0 and I'd like to increase it gradually to (say) 2.0, I have the following other fields to support this:
private double targetZoomLevel
private double zoomIncrement
I then have a Camera.SetZoom(double target, double increment) method that sets a desired furure zoom level, and then a Camera.Update() method that moves the current zoom level towards the target level, using the increment.
This all works well enough, but I'd really like to implement the same behaviour for other fields (e.g. camera world position, player size, player position, etc.). Using my current method, I'd need to add 2 additional 'support' fields for each field.
I'm pretty sure that my current solution is a sub-optimal, but not sure how to go about improving this. I was thinking about implementing a Property<T> class that encapulates this behaviour for a value, but not sure how to generalise an Update() method to move the current value towards its target.
Thanks!
What you're describing sounds very much like an animation. Animations are formal concepts in a couple of frameworks (CSS and WPF come to mind).
The goal of an animation is to transition something from one value to the next.
There are a variety of ways to make that transition. Sometimes you want a 2D point to follow a Bézier curve as the curve's t variable linearly changes from 0 to 1 over some period of time. Other times you want a color to transition smoothly from red to blue by going the long way around a color wheel.
Here's an interface that can abstract over that concept:
public interface IAnimation<T>
{
T Current { get; }
void Update(double progress); // progress is a number between 0 and 1
}
For example, if you want a 2D point to animate over a sine wave 800 units wide and 2 units tall:
public sealed class Point2DAnimation : IAnimation<Point2D>
{
public Point2D Current { get; private set; }
public void Update(double progress)
{
Current = new Point2D(progress * 800, Math.Sin(progress * Math.PI * 2));
}
}
There are also a variety of ways to drive the transition. A common way to drive it is to say "I want this animation to happen as smoothly as possible over X seconds". But sometimes you might want the animation to repeat from the beginning a few more times. Or perhaps you want the animation to run forward then backward then forward and so on forever.
We could define an interface to abstract over the different ways that an IAnimation<T> can be driven. And one implementation might internally have a timer that ticks frequently enough to give the illusion of smoothness as progress goes from 0 to 1 in proportion to the amount of time that has passed at the moment of each tick.
But I want to pause here for a moment and ask a question.
What does the consumer of the abstraction need from it?
If all your code needs is read access to a T and a method called Update(), then Property<T> sounds like your ticket:
public sealed class Property<T>
{
readonly Func<T, T> _update;
public Property(T initial, Func<T, T> update)
{
Value = initial;
_update = update;
}
public T Value { get; private set; }
public void Update()
{
Value = _update(Value);
}
}
That class encapsulates a readable value and gives you an Update() method to call. No need for an IAnimation<T> interface or any other fancy trappings. Of course you'll have to instantiate instances of Property<T> with an update delegate that does what you want. But you can add some static methods somewhere to set it up in the most common ways. For example:
public static class PropertyHelpers
{
public Property<double> CreateZoomLevelProperty(double initial, double increment, double target)
{
return new Property<double>(initial, old =>
{
var #new = old + increment;
if (increment > 0 && #new > target || increment < 0 && #new < target)
return target;
else
return #new;
});
}
}
On the other hand if you want to think of the value as a stream of values controlled by something else in the code and you only need to get read access to the values when they arrive, then perhaps IObservable<T> (and the Reactive NuGet package) is what you're after. For example:
public class Camera
{
double _zoomLevel;
public IDisposable UpdateZoomLevel(IObservable<double> zoomLevels)
{
return zoomLevels.Subscribe(zoomLevel => _zoomLevel = zoomLevel);
}
}
Of course then it becomes the responsibility of other code somewhere to come up with an IObservable<double> that publishes zoom levels in the fashion that you desire.
So I suppose my answer can be summed up as this:
It depends.
Disclaimer: Perhaps none of the code above will compile
I recently learned about design patterns and wanted to change my code for a small game I had to make. The game is called SpaceTaxi. I've made a parser, parsing a .txt file with ascii content resulting in 4 different lists of entities: taxi, obstacle, exit and platform. Inside the gameloop I call a big collision-method using these entities detecting whether they collide. It's really ugly code. Is there a good design pattern I could use for my collision method? So instead of having a big method then have smaller classes? Currently it looks like this:
/// <summary>
/// Checks for collision with obstacles, platforms and exits.
/// </summary>
private void CollisonCheck() {
var platformCollision = Player.CollisionPlatform(Parser.PlatformEntities,
false);
var obstacleCollision = Player.CollisionObstacle(Parser.ObstacleEntities,
false);
var exitCollision = Player.CollisionObstacle(Parser.ExitEntities,
false);
// Landing on platform
if (platformCollision.Item1 && obstacleCollision) {
// Stand still on platform
if (Math.Abs(Player.Entity.Shape.AsDynamicShape().Direction.Y)
< Constants.COLLISION_DISTANCE) {
Player.Shape.Direction.Y = 0;
Player.Shape.Direction.X = 0;
Player.OnPlatform = true;
// Explode because of too much speed
} else {
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
0.1f, 0.1f);
}
// Be rewarded in case player transports a customer
if (Player.HasCostumer) {
foreach (var customer in pickedUpCustomers) {
if (CorrectDestination(platformCollision.Item2,
customer.DestinationPlatform)) {
score.AddPoint(CurrentCustomer.RewardPoints);
customer.CanRemove = true;
Player.HasCostumer = false;
}
}
}
// Exit map
} else if (exitCollision) {
// Switch from one map to another
if (GameRunning.CurrentMap == "the-beach.txt") {
GameRunning.CurrentMap = "short-n-sweet.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
// Switch from one map to another
} else {
GameRunning.CurrentMap = "the-beach.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
}
GameRunning.Timer.Restart();
Parser.Load(GameRunning.CurrentMap);
allCustomersInMap = new List<Customer>();
foreach (var c in Parser.Customer) {
allCustomersInMap.Add(new Customer(c.Key, c.Value.Item1,
c.Value.Item2, c.Value.Item3, c.Value.Item4,
c.Value.Item5));
}
// Collision with obstacle. Add explosion
} else if (obstacleCollision) {
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
Constants.EXPLOSION_WIDTH, Constants.EXPLOSION_HEIGHT);
TaxiBus.GetBus()
.RegisterEvent(GameEventFactory<object>.CreateGameEventForAllProcessors(
GameEventType.GameStateEvent, this, "CHANGE_STATE",
"MAIN_MENU", ""));
}
// Collision with taxi and customer
// CollisionCustomer returns a bool (item1) and null/customer (item2)
if (Player.CollisionCustomer(allCustomersInMap).Item1 && !Player.HasCostumer) {
var customer = Player.CollisionCustomer(allCustomersInMap).Item2;
TaxiMeterTimer = new Stopwatch();
TaxiMeterTimer.Start();
CurrentCustomer = customer;
pickedUpCustomers.Add(customer);
allCustomersInMap.Remove(customer);
CurrentCustomer.SetPosition(Constants.HIDEPOS_X, Constants.HIDEPOS_Y);
Player.HasCostumer = true;
}
}
Please note that questions like this are better suited for CodeReview as this is pretty much off topic for SO because you do not have a specific problem or exception that you are trying to resolve.
It is good practise in all applications to separate out decision logic from action logic, for a number of reasons:
Removing the implementation of actions from complex logic trees makes it easier to visualise the decision process, you assume that the actions work correctly and debug them separately
Creating single purpose action methods promotes code re-use from different decision logic trees in your program
You can easily test and debug individual actions or logic branches without disrupting or being distracted by the bigger picture.
You can more clearly document your intent with method Doc Comments
Just separating out the actions you have defined results in code similar to this:
/// <summary>
/// Checks for collision with obstacles, platforms and exits.
/// </summary>
private void CollisonCheck()
{
var platformCollision = Player.CollisionPlatform(Parser.PlatformEntities, false);
var obstacleCollision = Player.CollisionObstacle(Parser.ObstacleEntities, false);
var exitCollision = Player.CollisionObstacle(Parser.ExitEntities, false);
// Landing on platform
if (platformCollision.Item1 && obstacleCollision)
DockAtPlatform(); // Stand still on platform
else if (exitCollision)
ExitMap(); // Exit map
else if (obstacleCollision)
CollideWithObject(); // Collision with obstacle. Add explosion
// ??? Player collision can occur at a platform or in general regions in the map
if (Player.CollisionCustomer(allCustomersInMap).Item1 && !Player.HasCostumer)
PickupCustomer();
}
/// <summary>
/// Dock Player with platform as long as they are not approaching too fast.
/// Collect reward if carrying a passenger
/// </summary>
/// <remarks>If too fast, player will explode!</remarks>
private void DockAtPlatform()
{
if (Math.Abs(Player.Entity.Shape.AsDynamicShape().Direction.Y)
< Constants.COLLISION_DISTANCE)
{
Player.Shape.Direction.Y = 0;
Player.Shape.Direction.X = 0;
Player.OnPlatform = true;
// Explode because of too much speed
}
else
{
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
0.1f, 0.1f);
}
// Be rewarded in case player transports a customer
if (Player.HasCostumer)
{
foreach (var customer in pickedUpCustomers)
{
if (CorrectDestination(platformCollision.Item2,
customer.DestinationPlatform))
{
score.AddPoint(CurrentCustomer.RewardPoints);
customer.CanRemove = true;
Player.HasCostumer = false;
}
}
}
}
/// <summary>
/// Switch between Maps
/// </summary>
private void ExitMap()
{
// Switch from one map to another
if (GameRunning.CurrentMap == "the-beach.txt")
{
GameRunning.CurrentMap = "short-n-sweet.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
}
else
{
// Switch the reverse way around
GameRunning.CurrentMap = "the-beach.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
}
GameRunning.Timer.Restart();
Parser.Load(GameRunning.CurrentMap);
allCustomersInMap = new List<Customer>();
foreach (var c in Parser.Customer)
{
allCustomersInMap.Add(new Customer(c.Key, c.Value.Item1,
c.Value.Item2, c.Value.Item3, c.Value.Item4,
c.Value.Item5));
}
}
/// <summary>
/// Show explosion because player has collided with an object, then return to the main menu
/// </summary>
private void CollideWithObject()
{
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
Constants.EXPLOSION_WIDTH, Constants.EXPLOSION_HEIGHT);
TaxiBus.GetBus()
.RegisterEvent(GameEventFactory<object>.CreateGameEventForAllProcessors(
GameEventType.GameStateEvent, this, "CHANGE_STATE",
"MAIN_MENU", ""));
}
/// <summary>
/// Pickup a new customer, start the meter running and remove the customer from the map
/// </summary>
private void PickupCustomer()
{
var customer = Player.CollisionCustomer(allCustomersInMap).Item2;
TaxiMeterTimer = new Stopwatch();
TaxiMeterTimer.Start();
CurrentCustomer = customer;
pickedUpCustomers.Add(customer);
allCustomersInMap.Remove(customer);
CurrentCustomer.SetPosition(Constants.HIDEPOS_X, Constants.HIDEPOS_Y);
Player.HasCostumer = true;
}
Now you can focus on the individual actions and review them to see if there are cleaner ways to code their process.
A few notes to consider:
Add Explosion should accept a point object instead of passing through the X,Y coordinates, it makes the code easier to read and is a natural way to pass coordinates that always go together.
Instead of using Tuples, you should create specific data model classes to use as return values from the collision functions, it feels like over-engineering, but it helps both with documentation of your code and to understand the intent.
Takes little time to define a class to hold the collision response, with minimal documentation, instead of burying inside comments what .Item1 and .Item2 might be in terms of data type and logical meaning
Yes Tuples are awesome, in terms of rapidly smashing code solutions out, but you always have to review the code that creates the values to understand or identify the meaning behind the values, so these are usually the first to be refactored out of my prototyping code when I want to get serious about a solution.
You have a style of placing the comments for the next if block inside the previous branch code, move the comments to inside the affected if branch, or immediately above it
Or move the branch into its own method and you can use Doc comments.
If the Player object itself holds the meter variables, you could accept multiple passengers (up to the capacity of the vehicle) and collect multiple fares on delivery, your action for dropping off a customer at a platform already assumes multiple passengers.
You may have already catered for this in different ways
Final Note (a personal one)
Try to change your method logic into more cause and effect style, you gain a lot of benefits in the overall SDLC if you adopt more functional programming styles into your OO logic. Where you can, and especially for the smallest units of work, pass in the objects that will be operated on as arguments for your methods rather than referencing global objects, in this way you will find it easier to establish unit testing and code review of your individual methods.
Even though in this project you may not implement unit tests, it is a very good habit to evolve, it will make future code examples that you post on SO easier for the rest of us to debug and will allow you to be a more efficient contributor in a team or community development project.
We're creating a game for a school project. It's a 2D platformer and it is in its very early stages. We use C#/XNA and we're implementing Farseer Physics Engine.
I'm currently struggling with the map-class. In the class we have a List of DrawableGameObjects, were we store each tile of the map and draw them. But when we try to draw them we get a "Assertion Failed". Examining the problem even further I've come to the conclusion that whenever we try to add more than to static bodies to the world (even without drawing them) we get this failure. Throw message
Game1.cs:line 210 is:
world.Step(0.033333f);
And Program.cs:line 15 is:
game.Run();
Here is the code for the Map class:
class Map
{
private List<DrawableGameObject> ground = new List<DrawableGameObject>();
public Map(World world, Texture2D texture)
{
for (int i = 0; i < 32; i++)
{
DrawableGameObject floor = new DrawableGameObject(world, texture, new Vector2(40, 40), 100, "ground");
floor.Position = new Vector2(i * 40, 500);
floor.body.BodyType = BodyType.Static;
ground.Add(floor);
}
}
public void Draw(SpriteBatch spriteBatch){
foreach (DrawableGameObject dgo in ground)
dgo.Draw(spriteBatch);
}
}
Any ideas? I've posted the problem on Farseer's forum, but they haven't been very helpful yet...
This is a bug in Farseer. (Version 3.3.1)
I opened up the Farseer source code to the method in question (World.SolveTOI) and found two calls to Debug.Assert. And, in fact, in my copy of the code, I've actually already come across this bug and commented one of them out, specifically:
Debug.Assert(typeA == BodyType.Dynamic || typeB == BodyType.Dynamic);
Basically it doesn't want to attempt to handle contacts between two bodies that are static.
Fortunately the code immediately below actually checks for essentially the same condition, and continues the loop if that is the case:
bool awakeA = bA.Awake && typeA != BodyType.Static;
bool awakeB = bB.Awake && typeB != BodyType.Static;
// Is at least one body awake?
if (awakeA == false && awakeB == false)
{
continue;
}
So it's quite safe to simply comment out or remove the assertion. (You should, of course, be building Farseer from source - it makes life much easier.)
To reproduce the Farseer bug: Have two static bodies and one dynamic body that is in contact with both, then make the dynamic body static. The assert will trigger.
The assert is in the contact handling loop. Normally a pair of static bodies wouldn't create contacts. But if a body starts out as dynamic, contacts can be created - they don't get removed when the body is made static.
I'm new to Reactive Extensions for .NET and while playing with it I thought that it would be awesome if it could be used for games instead of the traditional update-render paradigm. Rather than trying to call Update() on all game objects, the objects themselves would just subscribe to the properties and events they are interested in and handle any changes, resulting in fewer updates, better testability and more concise queries.
But as soon as, for example, a property's value changes, all subscribed queries will also want to update their values immediately. The dependencies may be very complex, and once everything is going to be rendered I don't know whether all objects have finished updating themselves for the next frame. The dependencies may even be such that some objects are continuously updating based on each other's changes. Therefore the game might be in an inconsistent state on rendering. For example a complex mesh that moves, where some parts have updated their positions and other have not yet once rendering starts. This would not have been a problem with the traditional update-render loop, as the update phase will finish completely before rendering starts.
So then my question is: is it possible to ensure that the game is in a consistent state (all objects finished their updates) just before rendering everything?
The short answer is yes, it is possible to accomplish what you're looking for regarding game update loop decoupling. I created a proof-of-concept using Rx and XNA which used a single rendering object which was not tied in any way to the game loop. Instead, entities would fire an event off to inform subscribers they were ready for render; the payload of the event data contained all the info needed to render a frame at that time for that object.
The render request event stream is merged with a timer event stream (just an Observable.Interval timer) to synchronize renders with the frame rate. It seems to work pretty well, and I'm considering testing it out on slightly larger scales. I've gotten it to work seemingly well both for batched rendering (many sprites at once) and with individual renders. Note that the version of Rx the code below uses is the one that ships with the WP7 ROM (Mirosoft.Phone.Reactive).
Assume you have an object similar to this:
public abstract class SomeEntity
{
/* members omitted for brevity */
IList _eventHandlers = new List<object>();
public void AddHandlerWithSubscription<T, TType>(IObservable<T> observable,
Func<TType, Action<T>> handlerSelector)
where TType: SomeEntity
{
var handler = handlerSelector((TType)this);
observable.Subscribe(observable, eventHandler);
}
public void AddHandler<T>(Action<T> eventHandler) where T : class
{
var subj = Observer.Create(eventHandler);
AddHandler(subj);
}
protected void AddHandler<T>(IObserver<T> handler) where T : class
{
if (handler == null)
return;
_eventHandlers.Add(handler);
}
/// <summary>
/// Changes internal rendering state for the object, then raises the Render event
/// informing subscribers that this object needs rendering)
/// </summary>
/// <param name="rendering">Rendering parameters</param>
protected virtual void OnRender(PreRendering rendering)
{
var renderArgs = new Rendering
{
SpriteEffects = this.SpriteEffects = rendering.SpriteEffects,
Rotation = this.Rotation = rendering.Rotation.GetValueOrDefault(this.Rotation),
RenderTransform = this.Transform = rendering.RenderTransform.GetValueOrDefault(this.Transform),
Depth = this.DrawOrder = rendering.Depth,
RenderColor = this.Color = rendering.RenderColor,
Position = this.Position,
Texture = this.Texture,
Scale = this.Scale,
Size = this.DrawSize,
Origin = this.TextureCenter,
When = rendering.When
};
RaiseEvent(Event.Create(this, renderArgs));
}
/// <summary>
/// Extracts a render data object from the internal state of the object
/// </summary>
/// <returns>Parameter object representing current internal state pertaining to rendering</returns>
private PreRendering GetRenderData()
{
var args = new PreRendering
{
Origin = this.TextureCenter,
Rotation = this.Rotation,
RenderTransform = this.Transform,
SpriteEffects = this.SpriteEffects,
RenderColor = Color.White,
Depth = this.DrawOrder,
Size = this.DrawSize,
Scale = this.Scale
};
return args;
}
Notice that this object doesn't describe anything how to render itself, but only acts as a publisher of data that will be used in rendering. It exposes this by subscribing Actions to observables.
Given that, we could also have an independent RenderHandler:
public class RenderHandler : IObserver<IEvent<Rendering>>
{
private readonly SpriteBatch _spriteBatch;
private readonly IList<IEvent<Rendering>> _renderBuffer = new List<IEvent<Rendering>>();
private Game _game;
public RenderHandler(Game game)
{
_game = game;
this._spriteBatch = new SpriteBatch(game.GraphicsDevice);
}
public void OnNext(IEvent<Rendering> value)
{
_renderBuffer.Add(value);
if ((value.EventArgs.When.ElapsedGameTime >= _game.TargetElapsedTime))
{
OnRender(_renderBuffer);
_renderBuffer.Clear();
}
}
private void OnRender(IEnumerable<IEvent<Rendering>> obj)
{
var renderBatches = obj.GroupBy(x => x.EventArgs.Depth)
.OrderBy(x => x.Key).ToList(); // TODO: profile if.ToList() is needed
foreach (var renderBatch in renderBatches)
{
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
foreach (var #event in renderBatch)
{
OnRender(#event.EventArgs);
}
_spriteBatch.End();
}
}
private void OnRender(Rendering draw)
{
_spriteBatch.Draw(
draw.Texture,
draw.Position,
null,
draw.RenderColor,
draw.Rotation ?? 0f,
draw.Origin ?? Vector2.Zero,
draw.Scale,
draw.SpriteEffects,
0);
}
Note the overloaded OnRender methods which do the batching and drawing of the Rendering event data (it's more of a message, but no need to get too semantic!)
Hooking up the render behavior in the game class is simply two lines of code:
entity.AddHandlerWithSubscription<FrameTicked, TexturedEntity>(
_drawTimer.Select(y => new FrameTicked(y)),
x => x.RaiseEvent);
entity.AddHandler<IEvent<Rendering>>(_renderHandler.OnNext);
One last thing to do before the entity will actually render is to hook up a timer that will serve as a synchronization beacon for the game's various entities. This is what I think of as the Rx equivalent of a lighthouse pulsing every 1/30s (for default 30Hz WP7 refresh rate).
In your game class:
private readonly ISubject<GameTime> _drawTimer =
new BehaviorSubject<GameTime>(new GameTime());
// ... //
public override Draw(GameTime gameTime)
{
_drawTimer.OnNext(gameTime);
}
Now, using the Game's Draw method may seemingly defeat the purpose, so if you would rather avoid doing that, you could instead Publish a ConnectedObservable (Hot observable) like this:
IConnectableObservable<FrameTick> _drawTimer = Observable
.Interval(TargetElapsedTime)
.Publish();
//...//
_drawTimer.Connect();
Where this technique can be incredibly useful is in Silverlight-hosted XNA games. In SL, the Game object is unavailable, and a developer needs to do some finagling in order to get the traditional game loop working correctly. With Rx and this approach, there is no need to do that, promising a much less disruptive experience in porting games from pure XNA to XNA+SL
This is potentially quite a general question about decoupling rendering from update in a game loop. This is something that networked games have to cope with already; "how do you render something that doesn't break the player's immersion when you don't actually know what's happened yet?"
One approach to this is to 'multi buffer' the scene graph, or elements of it, and actually render an interpolated version at a higher render frame rate. You still have to identify a point in your update when everything is finished for a particular time step, but it is no longer tied to the render. Instead you copy your update results to a new scene graph instance with a time stamp and get started on the next update.
It does mean that you are rendering with a lag, so may not be suitable for all types of game.
Why don't you use some kind of IScheduler to schedule your change subscriptions. Then you could have your main game loop step your scheduler implementation 16.6 ms every frame (assuming 60fps). The idea would be that it would execute any scheduled actions due in that time, so you could still use things like delay or throttle.
I'm still new to C#. Currently using .NET 3.5. I'm writing an online game, and my game engine needs to handle player requested unit movement. The units will move at different speeds and can have different destinations, so the actual time that the unit arrives (and the command completes) will differ widely.
My strategy is that the model will calculate the next move along a given path, and then queue a worker to execute around the same time the unit would be arriving at the location. The worker will update the unit, notify players, queue the next step, etc.
One of my biggest stumbling blocks was writing a worker thread that would conditionally execute a task. In the past my worker threads have just tried to run each task, in order, as quickly as possible. The other challenge is that unit moves might get queued that have earlier start times than any other task in the queue, so obviously, they would need to get moved to the front of the line.
This is what I have figured out so far, it works but it has some limitations, namely its 100ms sleep limits my command response time. Is there a pattern for what i'm trying to do, or am I missing something obvious?
Thank you!
public class ScheduledTaskWorker
{
List<ScheduledTask> Tasks = new List<ScheduledTask>();
public void AddTask(ScheduledTask task)
{
lock (Tasks)
{
Tasks.Add(task);
Tasks.Sort();
}
}
private void RemoveTask(ScheduledTask task)
{
lock (Tasks)
{
Tasks.Remove(task);
}
}
private ScheduledTask[] CopyTasks()
{
lock (Tasks)
{
return Tasks.ToArray();
}
}
public void DoWork()
{
while (!StopWorking)
{
ScheduledTask[] safeCopy = CopyTasks();
foreach (ScheduledTask task in safeCopy)
{
if (task.ExecutionTime > DateTime.Now)
break;
if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCallBack), task))
RemoveTask(task);
else
{
// if work item couldn't be queued, stop queuing and sleep for a bit
break;
}
}
// sleep for 100 msec so we don't hog the CPU.
System.Threading.Thread.Sleep(100);
}
}
static void ThreadPoolCallBack(Object stateInfo)
{
ScheduledTask task = stateInfo as ScheduledTask;
task.Execute();
}
public void RequestStop()
{
StopWorking = true;
}
private volatile bool StopWorking;
}
And the task itself...
public class ScheduledTask : IComparable
{
Action<Item> Work;
public DateTime ExecutionTime;
Item TheItem;
public ScheduledTask(Item item, Action<Item> work, DateTime executionTime)
{
Work = work;
TheItem = item;
ExecutionTime = executionTime;
}
public void Execute()
{
Work(TheItem);
}
public int CompareTo(object obj)
{
ScheduledTask p2 = obj as ScheduledTask;
return ExecutionTime.CompareTo(p2.ExecutionTime);
}
public override bool Equals(object obj)
{
ScheduledTask p2 = obj as ScheduledTask;
return ExecutionTime.Equals(p2.ExecutionTime);
}
public override int GetHashCode()
{
return ExecutionTime.GetHashCode();
}
}
I'm not disagreeing with Chris, his answer is probably more appropriate to your underlying problem.
However, to answer your specific question, you could use something equivalent to Java's DelayQueue, which looks to have been ported to C# here: http://code.google.com/p/netconcurrent/source/browse/trunk/src/Spring/Spring.Threading/Threading/Collections/Generic/DelayQueue.cs?spec=svn16&r=16
Your Task class would implement IDelayed then you could either have a single thread calling Take (which blocks while there are no items ready) and executing task, or pass them off to ThreadPool.QueueUserWorkItem.
That sounds dangerously brittle. Without knowing more about your game and its circumstances, it sounds like you could potentially drown the computer in new threads just by moving a lot of units around and having them do long-running tasks. If this is server-side code and any number of players could be using this at once, that almost guarantees issues with too many threads. Additionally, there are timing problems. Complex code, bad estimating, delays in starting a given thread (which will happen with the ThreadPool) or a slowdown from a lot of threads executing simultaneously will all potentially delay the time when your task is actually executed.
As far as I know, the majority of games are single-threaded. This is to cut down on these issues, as well as get everything more in sync. If actions happen on separate threads, they may receive unfair prioritization and run unpredictably, thereby making the game unfair. Generally, a single game loop goes through all of the actions and performs them in a time-based fashion (i.e. Unit Bob can move 1 square per second and his sprite animates at 15 frames per second). For example, drawing images/animating, moving units, performing collision detection and running tasks would all potentially happen each time through the loop. This eliminates timing issues as well, because everything will get the same priority (regardless of what they're doing or how fast they move). This also means that the unit will know the instant that it arrives at its destination and can execute whatever task it's supposed to do, a little bit at a time each iteration.