Проблемы с таймером или с логикой? - C#

Узнай цену своей работы

Формулировка задачи:

Господа, помогите начинающему: Есть объект

DynamicGameObject

, его тип содержит статический список всех подобных объектов

List GameObjects

, а так же список объектов, которым сообщена функция движения (

DynamicGameObject.Move.To(x,y,speed)

)

List MoveToObjects

MoveToObjects

обрабатывается в отдельном потоке, который создается функцией

Movement(iDel)

в статическом конструкторе. Поток проходит по списку, получает следующий объект, обрабатывает его движение за некоторый дискретный отрезок времени (

iDel

) Прогоняю тест на одном объекте с заданными параметрами, вычисляю теоретическое время движения, потом сравниваю с реальным и... Естественно не получаю равенства. Все бы ничего если бы разница была в сотых долях секунды (при iDel = 10 миллисекунд), но разница тем больше, чем меньше iDel. Так

при задержке в 10 миллисекунд:

Теоретическое время движения 10 сек Практическое время движения 15,59 сек

при задержке в 100 миллисекунд:

Практическое время движения 10,83 сек

при задержке в 200 миллисекунд:

Практическое время движения 9,95 сек

при задержке в 300 миллисекунд:

Практическое время движения 10,31 сек (Последний тест так же показывает, что время теста не является строго убывающей прогрессией зависящей от iDel. Наиболее точный результат, при точке финиша 100, получаем при iDel 310. Но точность пропадает если поставить координату например 80. При iDel меньше 5 программа так же ведет себя некорректно.) Помогите мне найти ошибку в логике программы или посоветуйте другой способ реализации движения.
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Xml;

class Server
{
    static void Main(string[] args)
    {
        //Console.Clear();
        //AsyncServer ConnectionServer = new AsyncServer(11100);
        Game Process = new Game();
        Console.ReadLine();
    }
}
 
class Game
{
    public Game()
    {
        //Random Rand = new Random();
        for (int i = 0; i < 1; i++) 
        {
            //new DynamicGameObject(Rand.Next() % 10, Rand.Next() % 10, "Object "+i).Move.To(Rand.Next() % 100, Rand.Next() % 100);
            new DynamicGameObject(0.0, 0.0).Move.To(0.0, 100.0);

        }
    }    
}

class GameObject
{
    public static List<GameObject> GameObjects = new List<GameObject>();
    public double x{ get; set; }
    public double y{ get; set; }
    public string name;
    
    public GameObject() {}
    public GameObject(double _x, double _y, string _name = null)
    {
        GameObjects.Add(this);
        name = _name == null ? "Object": _name;
        x = _x;
        y = _y;
        
        Console.WriteLine("{0} has created. Coords is ({1},{2})",name,x, y);
    }    
}
 
class DynamicGameObject : GameObject
{
    public class MoveToInfo
    {
        private DynamicGameObject MTO; //Parent Object
        public MoveToInfo(DynamicGameObject parent) { this.MTO = parent; }

        private double X { get; set; }
        private double Y { get; set; }
        private double sinA { get; set; }
        private double cosA { get; set; }
        private double speed { get; set; }
        private DateTime StartTime;
        private DateTime FinishTime;
        
        public int MStatus = 0;     /* 
                                     0 - not moved
                                     1 - added to list
                                     2 - 1st itr. of cycle passed
                                     3 - ready to delete
                                    */
 
    //=====================================Movement phases===================================
        //==============Phase 1: Add to List================
        public void To(double MTX, double MTY, double speed=10.0)
        {
            this.speed = speed;
           
            if (MTX != MTO.x || MTY != MTO.y)
            {                
                double _X = MTX - MTO.x;
                double _Y = MTY - MTO.y;
                double _Z = Math.Sqrt(_X * _X + _Y * _Y);
                double f = _Z / speed;
                
                X = MTX;
                Y = MTY;
                sinA = _Y / _Z;
                cosA = _X / _Z;
                
                Console.WriteLine("Theoretical time of motion {0} sec", f.ToString()); 
                
                if (MStatus != 1)
                {
                    lock (SomeMoveToObjects) 
                    {
                        SomeMoveToObjects.Add(MTO); 
                    }
                }
                MStatus = 1;
            }
        }
        //==============Phase 2: Step by Step===============
        public void Step(double Span)
        {
            if (MStatus == 1)
            {
                StartTime = DateTime.Now;
                Console.WriteLine("{3} started moving to {0},{1} in {2}", X, Y, StartTime, MTO.name);
                MStatus = 2;
            }
            MTO.x += (Math.Abs(MTO.x - X) >= Math.Abs(cosA * speed * Span)) ? cosA * speed * Span : X - MTO.x;
            MTO.y += (Math.Abs(MTO.y - Y) >= Math.Abs(sinA * speed * Span)) ? sinA * speed * Span : Y - MTO.y;
            Console.WriteLine("{0} move to ({1},{2})", MTO.name, MTO.x, MTO.y);
            if (MTO.x == X && MTO.y == Y)
            {
                MStatus = 3;
                //Console.WriteLine("{0} ready to finish in {1} for {2}", MTO.name, DateTime.Now, StartTime - DateTime.Now);
            }
            
        }
        //==============Phase 3: Remove from List===========
        public bool ReadyToRemove()
        {
            if (MStatus == 3) 
            {                
                FinishTime = DateTime.Now; 
                Console.WriteLine("{0} has finished to {2},{3} in {1} for {4}", MTO.name, FinishTime, MTO.x, MTO.y, StartTime - FinishTime); 
                MStatus = 0; 
                return true; 
            }
            else { return false; }
        }
    //=======================================================================================
    }
    public static void Movement(long iDel)
    {
        Timer ticker = new Timer(new TimerCallback((object state)=>
        {
            lock (MoveToObjects)
            {
                lock (SomeMoveToObjects) { MoveToObjects.AddRange(SomeMoveToObjects); SomeMoveToObjects.Clear(); }
                MoveToObjects.ForEach(MTO => MTO.Move.Step(iDel*0.001));
                MoveToObjects.RemoveAll(MTO => MTO.Move.ReadyToRemove());
            }
        }),null,0,iDel);
    }   
    
    public static List<DynamicGameObject> MoveToObjects = new List<DynamicGameObject>();
    public static List<DynamicGameObject> SomeMoveToObjects = new List<DynamicGameObject>();
    public static List<DynamicGameObject> ReadyToDeleteObjects = new List<DynamicGameObject>();
 
    public MoveToInfo Move;
    
    //===================================Конструкторы======================================
    static DynamicGameObject()
    {
        Movement(20);
    }
    public DynamicGameObject() : base() { Move = new MoveToInfo(this); }
    public DynamicGameObject(double _x, double _y, string _name = null): base(_x, _y, _name) 
    {
        Move = new MoveToInfo(this);    
    }
    //===================================================================================
        
}
Ну хорошо. Забудем о прошлом коде. Вот та же проблема в укороченной форме:
using System;
using System.Threading;
 
namespace App
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime ST = DateTime.Now, ET=DateTime.Now;
            double x =0.0, X=100.0;
            long iDel = 31;
            bool flag=true;
            Timer t = new Timer((object s) =>
            {
                if (flag) { ST = DateTime.Now; flag = false; }
                if (x < X){ x += iDel * 0.01;}
                else {ET = DateTime.Now; Console.WriteLine(ET - ST);}            
            }, null, 0, iDel);
            Console.ReadLine();
        }
    }
}
Лучший результат опять получаем при iDel = 31 или 310 Извините не разобрался как остановить таймер, если можно помогите заодно и с этой проблемой.

Решение задачи: «Проблемы с таймером или с логикой?»

textual
Листинг программы
using System;
using System.Threading;
using System.Diagnostics;
 
class Program
{
    static void Main(string[] args)
    {        
        double x = 0.0, X = 19.0;
        TimeSpan TT;
        Stopwatch Watch = new Stopwatch();
        Watch.Start();
        while (x < X)
        {
            TT = Watch.Elapsed;
            Thread.Sleep(10);
            x += (Watch.Elapsed.Subtract(TT).Ticks * 1E-7) * 10;
        }
        Watch.Stop();
        Console.WriteLine(Watch.Elapsed);
        Console.ReadLine();
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

15   голосов , оценка 4.133 из 5