1
\$\begingroup\$

I'm doing a game in Xaml WPF and I didn't really choose the tools and languages. It's to be hidden in a really big app with a lot of code.

The whole snake takes place in a simple xaml canvas and xaml.cs file here.

Actually, the snake became really laggy after being taller than 20 part, and even before the speed is absolutely not constant.

I don't know a lot about game programming but I'm doing software for a while now. How can I improve this game, make speed less dependent on snake size, and make it lag way less with the same computer perf?

I think the more important is the paintSnake method called every timer Tick.

private void paintSnake(Point currentposition)
{
    cleanSnake();
    paintSnakeHead(currentposition);
    paintSnakeBody(currentposition);
}
private void cleanSnake()
{
    var count = paintCanvas.Children.Count;
    var toDel = count - (NbBonus + 1);
    paintCanvas.Children.RemoveRange(NbBonus + 1, toDel);
}
private void paintSnakeHead(Point currentposition)
{
    var rot = GetRotation();
    RotateTransform aRotateTransform = new RotateTransform();
    aRotateTransform.CenterX = 0.5;
    aRotateTransform.CenterY = 0.5;
    aRotateTransform.Angle = rot;
    _headBrush.RelativeTransform = aRotateTransform;
    Rectangle headRect = new Rectangle();
    headRect.Fill = _headBrush;
    headRect.Height = headSize;
    headRect.Width = headSize;
    Canvas.SetTop(headRect, currentposition.Y);
    Canvas.SetLeft(headRect, currentposition.X);
    //On decale tout les point du snake
    snakePoints.Insert(0, currentposition);
    paintCanvas.Children.Add(headRect);
    int count = snakePoints.Count;
    // Restrict the tail of the snake
    if (count > length)
    {
        snakePoints.RemoveAt(length);
    }
}
private int GetRotation()
{
    switch (direction)
    {
        case (int)MOVINGDIRECTION.DOWNWARDS:
            return 180;
        case (int)MOVINGDIRECTION.UPWARDS:
            return 0;
        case (int)MOVINGDIRECTION.TOLEFT:
            return 270;
        case (int)MOVINGDIRECTION.TORIGHT:
            return 90;
        default:
            return 0;
    }
}
private void paintSnakeBody(Point currentposition)
{
    for (int i = 1; i < snakePoints.Count; i++)
    {
        //On ne dessinne un cercle que tout les headsize position
        if (i % headSize == 0)
        {
            Rectangle bodyRect = new Rectangle();
            bodyRect.Fill = _bodyBrush;
            bodyRect.Height = headSize;
            bodyRect.Width = headSize;
            Canvas.SetTop(bodyRect, snakePoints[i].Y);
            Canvas.SetLeft(bodyRect, snakePoints[i].X);
            paintCanvas.Children.Add(bodyRect);
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Its 330 line not to big for a snippet? :S \$\endgroup\$ – Jebik Aug 24 '17 at 15:41
  • \$\begingroup\$ Personally, it is not a problem if your code is on GitHub, but the policy of this website states you must include it on your question, otherwise more reputed users will close your question. \$\endgroup\$ – Billal Begueradj Aug 24 '17 at 15:45
  • \$\begingroup\$ Format left please \$\endgroup\$ – paparazzo Aug 24 '17 at 16:18
  • \$\begingroup\$ I am wondering if paint a grid and then just fill in or clear would not be faster? \$\endgroup\$ – paparazzo Aug 24 '17 at 16:21
  • \$\begingroup\$ Where is snakePoints defined? \$\endgroup\$ – paparazzo Aug 24 '17 at 16:27
6
\$\begingroup\$

I'm going to review only the code in your post.


You don't use WPF as you have to. In WPF you don't need to perform clear/draw sequence. The right way is to use MVVM and update coordinates of the snake's blocks in view-model. In XAML you will have ItemsControl with Canvas as its panel. ItemsSource should be bound to collection of blocks and each item should have bindings for Canvas.Top and Canvas.Left.

In fact each item will be wrapped to ContentPresenter where there is no your bindings to coordinates, so you can consider to write your custom Canvas-based panel which will search for coordinates in each child.

I'm just describing the right way you should work with WPF, there are variants how you'll implement all this stuff.


This naming of enum and its fields is wrong:

MOVINGDIRECTION.DOWNWARDS
MOVINGDIRECTION.UPWARDS
MOVINGDIRECTION.TOLEFT
...

You should follow naming guidelines for types and public members:

MovingDirection.Down
MovingDirection.Up
MovingDirection.Left
...

What is the purpose of casting enum values to int?

case (int)MOVINGDIRECTION.DOWNWARDS:

Yes, I see on your GitHub repo that all your direction fields have type of int. But why? Let those fields be of MovingDirection type.


Also I suggest to go away from your switch and use Dictionary:

private static readonly Dictionary<MovingDirection, int> RotationAngles =
    new Dictionary<MovingDirection, int>
{
    [MovingDirection.Down] = 180,
    [MovingDirection.Up] = 0,
    [MovingDirection.Left] = 270,
    [MovingDirection.Right] = 90,
};

private int GetRotation()
{
    return RotationAngles.TryGetValue(direction, out var angle)
        ? angle
        : 0;
}

But it's just another way. switch is not a problem in your case since there are only 4 possible directions and this situation will not be changed in the future.

\$\endgroup\$
  • \$\begingroup\$ It's the first time i post to code review and i'm surprise because this actually help a lot. So about naming and dictionary i will change this because its so much clear. And about moving canvas element i have think about it but not done it already because i must change a bit my way of thinking. But i will do this tonight and see if performance are better \$\endgroup\$ – Jebik Aug 25 '17 at 9:11
  • \$\begingroup\$ And about why i have int.... Not real reason i decide to use a int 0 for no direction instead of adding enum None... Bad choice i must change that to no need int for direction in my case \$\endgroup\$ – Jebik Aug 25 '17 at 9:25
  • \$\begingroup\$ @Jebik None is a good choice so don't be afraid of it :) \$\endgroup\$ – Maxim Aug 25 '17 at 10:14
  • \$\begingroup\$ I have change the code a lot since this morning... But i can't really test it. I think its more optimize. But i would like to have a review in the whole code to help me continue to improve it a bit. And about what i saw in help center it's not really appropriate here. Are they any site in stackExchange community where i can get this? I have stopped use int. stopped deleting and redraw every part every tick. Added a notion of fluidit to move 1/4Box instead of 1 pixel each Timer Tick.... But i think it still have some big mistake for a first game. \$\endgroup\$ – Jebik Aug 25 '17 at 14:07
  • \$\begingroup\$ You are still not using MVVM. It is the big mistake in WPF app development :) \$\endgroup\$ – Maxim Aug 25 '17 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.