Move it soldier, or player to player collisions

There is a need to differentiate between collision types. There should be different behaviour when player collides with bullet and different if two players collide with each other. That is unless we assume players have bayonettes, which I don’t. With bullets it is pretty straightforward – bullet and player are eliminated from game. But what when two players meet? The idea itself is simple, players need to be moved back a little bit, just enough for them to no longer collide. But player’s move cannot be completly canceled – that would possibly take him too far out, leaving space between players and not making great user experience. Who likes invisible walls, right?

Fortunately the solution is not too complex. Again – circles make it so easy. We do have two circles that are colliding. This means that there is ceratin part of both circles that overlaps. What needs to be done is – I need to have distance at which the circles overlap and vector at pointing back from the collision direction to indicate how far player that caused collision needs to be moved back. And it is very similar to what I was doing in collisions already – I calculate distance between two objects using vector pointing from center of one object to center of the other. I also have distance between those objects – this is just a sum of ther radii. But how do I get vector pointing out of collision?

Circles colliding with each other and collision solution vector calculated

Circles colliding with each other and collision solution vector calculated

If I have distance between players and sizes of them – the difference between two values (distance – sum of radii) will be distance at which objects collide. Since I also have distance vector, all I need to do is to take unit vector of distance and scale it to the size of collision distance. But will the direction of vector be right? Sure it will. At first the vector is calculated to point from source object (say player A) to target object (player B that is). And since distance between players is smaller then sum of radii (that’s the only case in which collision is detected), subtracting those numbers will give negative value. Scale distance unit vector by this and in return you will get nice pointy vector pushing player out of player’s B personal space. Well, this explanation got long, but the idea presented in code is ultra simple. Just look:

private void HandleCollision(Player o1, Player o2)
{
    var distanceVector = new Vector2d(o2.Position.X - o1.Position.X, o2.Position.Y - o1.Position.Y);
    var distance = distanceVector.Length();
    var collisionLength = distance - (o1.Size + o2.Size);

    var collisionFixVector = distanceVector.Unit().Scale(collisionLength);

    o1.Position = o1.Position.Add(collisionFixVector);
}

And just one small piece – to figure out which collision handling method to use, and it is done.

private void CalculateCollisions(IGameObject o1)
{
    foreach (var o2 in GameObjects)
    {
        if (o1 == o2) continue;
        if (ObjectsCollide(o1, o2))
        {
            HandleCollision(o1, o2);
        }
    }
}

private bool ObjectsCollide(IGameObject o1, IGameObject o2)
{
    var distanceVector = new Vector2d(o2.Position.X - o1.Position.X, o2.Position.Y - o1.Position.Y);
    return distanceVector.Length() < o1.Size + o2.Size;
}

private void HandleCollision(IGameObject o1, IGameObject o2)
{
    if (o1 is Player && o2 is Bullet)
        HandleCollision(o1 as Player, o2 as Bullet);
    else if (o1 is Bullet && o2 is Player)
        HandleCollision(o2 as Player, o1 as Bullet);
    else if (o1 is Player && o2 is Player)
        HandleCollision(o1 as Player, o2 as Player);
}

private void HandleCollision(Player o1, Bullet o2)
{ ... }

private void HandleCollision(Player o1, Player o2)
{ ... }

Very simple, maybe will replace it with something smarter later on, but now it works like a charm.

Also note that I changed collision detection to take object as parameter. That is to change when collisions are calculated – now they are done immediately after the object moves. This is so that I can tell which object to move back – obviously this needs to be the one that caused collision by moving.

And that’s it – players won’t disappear after touching no more, but rather will slide around each other.

Collision detection

What fun would be the game where you can shoot but can’t hit anything? No fun at all. Therefore there has to be some mechanism to calculate collisions between objects in system.

private void CalculateCollisions()
{
    foreach (var o1 in GameObjects)
        foreach (var o2 in GameObjects)
        {
            if (o1 == o2) continue;
            if (ObjectsCollide(o1, o2))
            {
                if (o1 is IDestroyable)
                    ((IDestroyable)o1).IsDestroyed = true;

                if (o2 is IDestroyable)
                    ((IDestroyable)o2).IsDestroyed = true;
            }
        }
}

private bool ObjectsCollide(IGameObject o1, IGameObject o2)
{
    var distanceVector = new Vector2d(o2.Position.X - o1.Position.X, o2.Position.Y - o1.Position.Y);
    return distanceVector.Length() < o1.Size + o2.Size;
}

The code above is prety simple. Fortunately in my system all objects are round (what a genious design decision, right?), which makes collision detection extremly efficient and precise. What you do is – calculate distance between center points of both circles and compare them to sum of their radii (what a cool word, plural of radius, way cooller than radiuses). I don’t think it can get any simpler than that.

When I have collision, I do one thing – destroy each object that can be destroyed. For this I have marked player as destroyable as well – player would like to get some points after hitting other player, not just his or her bullets.

There are bunch of problems with this solution though. First it is O(n^2), I do iterate over objects twice to get my results. This also means I will detect collisions two times – after all if A collides with B – B will collide with A as well. I am also checking agains all objects all over the game arena, which may get quite big. That means a lot of collisions to check against, most of which seem ridiculous – what’s the point of checking collision with player who’s 200 units away from bullet.

It has one benefit though – it works and it is like 20 lines of code, works as starting point.

No, mr Bullet, I expect you to die

There are some objects that I want to live for some time and then disappear. Bullets would be one of them. They serve a purpose for a time, but once they (a) hit another object, or (b) reach their lifespan, they should disappear. My first idea was to store creation time, get actual time and check whether the lifespan of bullet is reached. What sounded like a good idea at first, and actually worked on server side, is quite hard to do on client side. Well, to do it is easy. The hard part is synchronizing client and server time. And this would be priority – getting time wrong would mean client side would render bullet for too long or too short. Either way it would be terrible experience.

And then, while cleaning my teeth, it hit me. I was looking at this completely wrong. I’m not interested in how much time has passed since object creation. What I want to know is how long object has to live. Basically Time To Live, similar to what you might know from pinging or other web protocols. And implementation is even simpler.

public void Update(DateTime updateTime)
{
    if (TimeToLive <= 0)
    {
        IsDestroyed = true;
        return;
    }

    var changeTime = updateTime;
    var timeBetweenEvents = changeTime - lastUpdate;

    Position.X += Speed.X * timeBetweenEvents.TotalSeconds;
    Position.Y += Speed.Y * timeBetweenEvents.TotalSeconds;

    TimeToLive -= (int)timeBetweenEvents.TotalMilliseconds;
    lastUpdate = changeTime;
}

And on client side as well:

var processFrame = function (timestamp) {
    if (!lastFrameTime)
        lastFrameTime = timestamp;

    var timeDiff = (timestamp - lastFrameTime) / 1000;

    for (var i = 0; i < gameObjects.length; i++) {
        var gameObject = gameObjects[i];

        if (!gameObject.IsDestroyed) {
            var directionPoint = { x: gameObject.Position.X + gameObject.FacingDirection.X, y: gameObject.Position.Y + gameObject.FacingDirection.Y };
            gameObject.Position.X += gameObject.Speed.X * timeDiff;
            gameObject.Position.Y += gameObject.Speed.Y * timeDiff;
            gameObject.FacingDirection = calculateFacingDirection(gameObject, directionPoint);

            if (!!gameObject.TimeToLive) {
                gameObject.TimeToLive -= timestamp - lastFrameTime;
                if (gameObject.TimeToLive <= 0)
                    gameObject.IsDestroyed = true;
            }
        }
    }

    gameObjects = gameObjects.filter(function (g) { return !g.IsDestroyed });

    gfx.drawArena(gameObjects);

    lastFrameTime = timestamp;
    requestAnimationFrame(processFrame);
};

Once again it has been proven that oral hygiene is goon not just for your teeth but your whole body!

Fire at will, pt 3

All that’s left is to limit spped of shooting for player. Producing possibly dozens of bullets every second is not what I want in my game. At some point there may be weapons that will allow shooting different amount of bullets per second, then I will simply change my mechanism to support that. Right now there needs to be basic solution in place.

And with a little thinking it seems to be realy easy to achieve. I have the time when the shot happened, I can store last shot time and just check if this happens to be earlier than available shooting rate.

public IEnumerable<IGameObject> ProcessInput(PlayerInput input, DateTime updateTime)
{
    ProcessDirection(input.KeysInput);
    FacingDirection = input.FacingDirection;

    var createdObjects = new List<IGameObject>();

    if (input.KeysInput.HasFlag(KeysInput.MouseLeft))
    {
        Shoot(createdObjects, updateTime);
    }

    return createdObjects;
}

private DateTime _lastShot = DateTime.Now;
private void Shoot(List<IGameObject> createdObjects, DateTime shotTime)
{
    if (shotTime - _lastShot < TimeSpan.FromMilliseconds(500))
        return;

    var bullet = Bullet.Create(Position.X, Position.Y, FacingDirection);
    Bullets.Add(bullet);
    createdObjects.Add(bullet);

    _lastShot = shotTime;
}

And small modification to hub to pass update time parameter correctly. This may become usefull later as well, for other actions.

public void PlayerMoving(PlayerInput input)
{
    var updateTime = DateTime.Now;
    UpdateGameState(updateTime);
    var player = players[Context.ConnectionId];
    var createdObjects = player.ProcessInput(input, updateTime);
    gameObjects.AddRange(createdObjects);
    Clients.All.PlayerMoved(gameObjects);
}

private void UpdateGameState(DateTime? updateTimestamp = null)
{
    var updateTime = updateTimestamp ?? DateTime.Now;

    foreach (var player in gameObjects)
        player.Update(updateTime);
}

If input processing happens, there is update time created in call and passed to input processing as well as game state updating. If other events are processed, game state update will get the time to use in calculations.

Fire at will, pt 2

OK, time to do some changes. I would really hate it if I had to write different loops for every possible object type. One loop to rule them all. One loop to draw them.

I’ve already extracted IGameObject interface with some common stuff I (at this point) think all objects will use. That is:

public interface IGameObject
{
    Guid Id { get; }
    Vector2d Position { get; }
    Vector2d Speed { get; }
    Vector2d FacingDirection { get; }

    void Update(DateTime updateTime);
}

Then I changed how hub manages objects:

public class RaimHub : Hub
{
    private static Dictionary<string, Player> players = new Dictionary<string, Player>();
    private static List<IGameObject> gameObjects = new List<IGameObject>();

    public void Register(string name)
    {
        name = HttpUtility.HtmlEncode(name);
        var player = Player.Create(name, 250, 250);
        players.Add(Context.ConnectionId, player);
        gameObjects.Add(player);
        Clients.All.Registered(player);
        Clients.Caller.OtherPlayers(players.Values.Where(p => p.Name != name));

        UpdateGameState();
        Clients.All.PlayerMoved(gameObjects);
    }

    public void SignOff()
    {
        ...

        UpdateGameState();
        Clients.All.PlayerMoved(gameObjects);
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        SignOff();
        return base.OnDisconnected(stopCalled);
    }

    public void PlayerMoving(PlayerInput input)
    {
        UpdateGameState();
        var player = players[Context.ConnectionId];
        var createdObjects = player.ProcessInput(input);
        gameObjects.AddRange(createdObjects);
        Clients.All.PlayerMoved(gameObjects);
    }

    private void UpdateGameState()
    {
        var updateTime = DateTime.Now;

        foreach (var player in gameObjects)
            player.Update(updateTime);
    }
}

So now any action that comes to server causes objects to be updated and sent back to all players to synchronise their status. This piece of code I’m positive will change, but servers its purpose for now.

It also requires some changes on client side. First at arena.js

var playerMoved = function (gameObjectsFromServer) {
    gameObjects = gameObjectsFromServer;
};

    var processFrame = function (timestamp) {
    if (!lastFrameTime)
        lastFrameTime = timestamp;

    var timeDiff = (timestamp - lastFrameTime) / 1000;

    for (var i = 0; i < gameObjects.length; i++) {
        var player = gameObjects[i];

        var directionPoint = { x: player.Position.X + player.FacingDirection.X, y: player.Position.Y + player.FacingDirection.Y };
        player.Position.X += player.Speed.X * timeDiff;
        player.Position.Y += player.Speed.Y * timeDiff;
        player.FacingDirection = calculateFacingDirection(player, directionPoint);
    }

    gfx.drawArena(gameObjects);

    lastFrameTime = timestamp;
    requestAnimationFrame(processFrame);
};

And then at raimGraphics.js

var drawArena = function (gameObjects) {
    drawingContext.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < gameObjects.length; i++) {
        var gameObject = gameObjects[i];
        if (gameObject.Name === undefined) {
            drawBullet(gameObject);
        } else {
            drawPlayer(gameObject);
        }
    }
};

Don’t shoot for this ugly if. Right now Name is only available for players, not for other objects so it can be used to differentiate between object types. But I will implement object types for sure!

There, now it makes things bit easier to handle on client and server.

Lets go back to handling user input. Last implementation of mouse click was working only when mouse was moving – that’s the only time mousemove is triggered of course. That’s not acceptable for shooting though. New, upgraded code looks like this:

function mouseDown(e) {
    if ((e.buttons && 1) && (keys.indexOf(1) === -1)) {
        keys.push(1);
    }
    notifyKeysChanged();
}

function mouseUp(e) {
    if (keys.indexOf(1) >= 0) {
        keys.splice(keys.indexOf(1), 1);
    }
    notifyKeysChanged();
}

(function () {
    document.addEventListener("keydown", keyDown);
    document.addEventListener("keyup", keyUp);
    document.addEventListener("mousemove", mouseMove);
    document.addEventListener("mousedown", mouseDown);
    document.addEventListener("mouseup", mouseUp);
})();

So mouse clicks are handled separately to all other moving logic, giving quick response and appropriate behavior.

Am I done with mouse input for now? Sure not. User can trigger so many shots one after another that he or she can fill up the screen with black dots. This is problem for game as well as for performance. I’ll need to handle that next.

Fire at will, pt. 1

With players moving and all, it is time to introduce some action! I hope to see some pixels flying all over the place, and see all those players respawning like crazy. But to get that, there needs to be a way to fire some projectiles, right?

function mouseMove(e) {
    var targetRect = document.getElementById("arena").children[0].getBoundingClientRect();
    mouseCoordinates = { x: e.clientX - targetRect.left, y: e.clientY - targetRect.top };
    mouseCoordinates.x = mouseCoordinates.x - args.viewport.x;
    mouseCoordinates.y = -(mouseCoordinates.y - args.viewport.y);
    console.log(e.buttons);
    if (e.buttons && 1) {
        keys.push(1);
    }
    else if (keys.indexOf(1) >= 0) {
        keys.splice(keys.indexOf(1), 1);
    }

    args.inputChanged({ direction: buildDirectionKey(), mouse: mouseCoordinates });
}

What has been added is handling mouse button pressed events. Well, to be precise – I get the info about mouse buttons state with mouse move event, which is handy. I use this to push the value 1 to list of keys pressed. This is safe since no keyboard keys can cause 1 to be added – this is not printable character. Simple, consistent. I’ve also added LeftMouse: 16 into my enum-like object holding keys map. This all get send to server. And what it does is:

in RaimHub.cs

public void PlayerMoving(PlayerInput input)
{
    UpdatePlayers();
    var player = players[Context.ConnectionId];
    var createdObjects = player.ProcessInput(input);
    gameObjects.AddRange(createdObjects);
    Clients.All.PlayerMoved(player, createdObjects);
}

in Player.cs

public IEnumerable<IGameObject> ProcessInput(PlayerInput input)
{
    ProcessDirection(input.KeysInput);
    FacingDirection = input.FacingDirection;

    if (input.KeysInput.HasFlag(KeysInput.MouseLeft))
    {
        var bullet = Bullet.Create(Position.X, Position.Y, FacingDirection);
        return new[] { bullet };
    }

    return Enumerable.Empty<IGameObject>();
}

And last, but not least, Bullet.cs

public class Bullet : IGameObject
{
    private DateTime lastUpdate = DateTime.Now;

    public Guid Id { get; private set; }
    public Vector2d Position { get; set; }
    public Vector2d Speed { get; set; }
    public Vector2d FacingDirection { get; set; }

    private Bullet() { }

    public static Bullet Create(double x, double y, Vector2d direction)
    {
        return new Bullet()
        {
            Id = Guid.NewGuid(),
            Position = new Vector2d(x, y),
            Speed = direction.Unit().Scale(10),
        };
    }

    public void Update(DateTime updateTime)
    {
        var changeTime = updateTime;
        var timeBetweenEvents = changeTime - lastUpdate;

        Position.X += Speed.X * timeBetweenEvents.TotalSeconds;
        Position.Y += Speed.Y * timeBetweenEvents.TotalSeconds;

        lastUpdate = changeTime;
    }
}

And also drawing on client side, we can’t forget drawing:

var drawArena = function () {
    drawingContext.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < players.count(); i++) {
        var gameObject = players.get(i);
        drawPlayer(gameObject);
    }

    for (var i = 0; i < gameObjects.length; i++) {
        var gameObject = gameObjects[i];
        drawingContext.beginPath();

        drawingContext.fillStyle = "rgba(0, 0, 0, 1)";
        x = gameObject.Position.X - viewport.x;
        y = gameObject.Position.Y - viewport.y;

        drawingContext.arc(x, -y, 2, 0, 2 * Math.PI);
        drawingContext.fill();
        drawingContext.closePath();
    }
};

Easy, right? I’m not entirely sure about my design decissions yet. Well, I’m pretty sure that this is not all OK and it will soon change, but for the moment it gets things done.

But what is so bad about it? Well, to start – there are separate collections of players and game objects, handled separately in drawing. And nobody likes special cases, right? I imagine this should be all handled the same way – just a list of objects that take action in game, possibly with each object knowing how to paint itself (or, more reasonably, specialized classes responsible for drawing all different projects).

Second thing is – my bullets don’t move. This is related to first thing. With separate collection of game objects, I did not write code that triggers bullets update.

Third – mouse clicks are only detected when mouse is moving. Take that campers! But no, for real that is an issue that needs to be handled.

In all honesty I’ve made a piece of code that makes player drop black dots when moving mouse. That’s not gonna sell. But I’m not finished yet.

Hands free CSS – no pixels

Some time ago I watched this great video: https://youtu.be/zdI2Z64Jdw8 . Seriously – if you are doing front end html and css, go and watch it, it is great. Basically what guy is showing is how to get responsive pages that will adjust to screen size without using media queries. While I’m pretty certain it is not always worth doing, I do think it is worth trying out first on side projects.

Now I’m not doing front end all that much. I can write html and css to do the things I want them to, but more often than not I need to use big hammer to make it all fit in place. Raim on the other hand is so small and simple that I decided to give it a try and not use any media queries for now (not that I have used any to this point) as well as to avoid absolute units. So no pixels for you, mister!

There are just a few things at this point I want to position on the page. Those are: name of the application along with competition logo, list of players and game arena, where canvas is injected. Before today the code looked like this:

.titleSection {
    position: fixed;
    left:    10px;
    bottom:  7px;
    opacity: 0.3;
    font-weight: bold;
    /*transition: opacity ease-in .2s;*/
}

.titleSection:hover {
    opacity: 0.9;
}

.dsp2016 {
    background-image: url(/Content/DSP2016.png);
    background-size: contain;
    width: 21px;
    height: 48px;
    display: inline-block;
}

#playersList {
    opacity: 0.7;
    font-size: small;
    display: inline-block;
    position: absolute;
    bottom: 70px;
}

#arena {
    z-index: -1;
    border: 1px solid black;
    position: fixed;
    top:    5px;
    right:  5px;
    bottom: 5px;
    left:   5px;
}

Some pixels are creeping out. Positioning content some pixels above or below will most likely fail on screens with higher dpi. Well, it will still work, but it might not put as much spacing between elements as I would like. Size of logo, too, should be responsive and adjust itself, to always be visible, but not get too big.

After improvements page looks pretty much the same way it did before, but the css file now has this inside of it:

.titleSection {
    position: fixed;
    left:    1em;
    bottom:  0.5em;
    opacity: 0.3;
    font-weight: bold;
    transition: opacity ease-in .2s;
}

.titleSection:hover {
    opacity: 0.9;
}

.dsp2016 {
    background-image: url(/Content/DSP2016.png);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    width: 2em;
    height: 2.5em;
    display: inline-block;
}

#playersList {
    opacity: 0.7;
    font-size: smaller;
    display: inline-block;
    position: absolute;
    bottom: 5em;
    left: 1em;
}
    #playersList span {
        display:block;
    }

#arena {
    z-index: -1;
    border: 0.1em solid black;
    position: fixed;
    top:    0.3em;
    right:  0.3em;
    bottom: 0.3em;
    left:   0.3em;
}

First look at dsp2016 class. Width and height are in relative units, 2.5×2 units in size, with also added no repeat and centering of background image. This places the image nicely, with some spacing around it. All the positions of other elements are also relative to font size now. I can now preserve the ratio of view with simply changing body font size. All will stay in the same relation to each other, players list and game logo will stay inside bordered game arena, never overlaying each other.