I am making a BCI interface, where the buttons must flicker at specific frequencies, at the moment I am using the System.Windows.Timer, however this is not very precise, and the flickering is not the frequency specified. The class I have used to make the flickering buttons are:
StateWithColor[] colors = new StateWithColor[] {
new StateWithColor(0, Color.Black),
new StateWithColor(1, Color.White)
};
public class FlickTimer<T> : IDisposable
where T : Control
{
public T Target { get; set; }
protected readonly IList<StateWithColor> possibleStates = new List<StateWithColor>();
protected int currentState = 0;
//protected int currentState_2 = 1;
protected object lockState = new object();
protected Timer timer = new Timer();
protected void Flicker(object sender, EventArgs e)
{
if (Target == null)
{
return;
}
if (Target.InvokeRequired)
{
Target.Invoke(new EventHandler(Flicker), sender, e);
return;
}
lock (lockState)
{
Target.BackColor = possibleStates[currentState].Color;
//int color = currentState + 1;
//Target.ForeColor = possibleStates[currentState_2].Color;
currentState++;
//currentState_2--;
if (currentState >= possibleStates.Count)
{
currentState = 0;
//currentState_2 = 1;
}
}
}
public FlickTimer(StateWithColor[] states, int timeout = 0, T target = null)
{
Target = target;
lock (lockState)
{
foreach (var state in states)
{
possibleStates.Add(state);
}
}
timer.Interval = timeout;
timer.Tick += Flicker;
Start();
}
public void Start()
{
timer.Start();
}
public void Stop()
{
timer.Stop();
}
public void Dispose()
{
if (timer != null)
{
Stop();
timer.Tick -= Flicker;
timer = null;
}
}
}
public struct StateWithColor
{ public int State;
public Color Color;
public StateWithColor(int state, Color color)
{
Color = color;
State = state;
}
}
This does not give the frequency I have specified when I run the Interface. The screen used for the interface is set to 120HZ, and the interface contains 9 buttons, which should be at the following frequencies: 6, 6.5, 7, 7.5, 8, 9, 10, 11, 12.5. Or nine frequencies with in the span of 6-15HZ. The frequencies can be 6.546 or 6.5 does not matter.
Is there a way to make this, and get a flivkering with the exact frequency?
Related
I am creating a blackjack game and have used a tutorial from the internet to get to this point. However, I have completed the tutorial and I have been left to add all the methods from other classes into the class where the blackjack game will be played and cannot figure out how to add the methods.
I Would like to know how i would go about adding all the methods to the P1 Class.
{
public class Card
{
public enum CardValue
{
Ace = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13
}
public enum CardSuit
{
Hearts = 1,
Spades = 2,
Clubs = 3,
Diamonds = 4
}
Image image;
CardValue cardValue;
CardSuit suit;
public Image Image
{
get
{
return this.Image;
}
}
public CardValue Value
{
get
{
return this.cardValue;
}
set
{
this.cardValue = value;
GetImage();
}
}
public CardSuit Suit
{
get
{
return this.suit;
}
set
{
this.suit = value;
GetImage();
}
}
public Card()
{
cardValue = 0;
suit = 0;
image = null;
}
private void GetImage()
{
if (this.Suit != 0 && this.Value != 0)
{
int xAxis = 0;
int yAxis = 0;
int height = 97;
int width = 73;
switch (this.Suit)
{
case CardSuit.Hearts:
yAxis = 196;
break;
case CardSuit.Spades:
yAxis = 98;
break;
case CardSuit.Clubs:
yAxis = 0;
break;
case CardSuit.Diamonds:
yAxis = 294;
break;
}
xAxis = width * ((int)this.Value - 1);
Bitmap src = Resources.cards;
Bitmap img = new Bitmap(width, height);
Graphics gr = Graphics.FromImage(img);
gr.DrawImage(src, new Rectangle(0, 0, width, height), new Rectangle(xAxis, yAxis, width, height), GraphicsUnit.Pixel);
gr.Dispose();
this.image = img;
}
}
}
}
{
public class deck
{
private List<Card> cards;
public List<Card> Cards
{
get { return cards; }
set { Cards = value; }
}
public deck()
{
Cards = new List<Card>();
ShuffleNewDeck();
}
public void ShuffleNewDeck()
{
cards.Clear();
for (int i = 1; i < 5; i++)
{
for (int f = 1; f < 14; f++)
{
Card card = new Card();
card.Value = (Card.CardValue)f;
card.Suit = (Card.CardSuit)i;
}
}
Random r = new Random();
cards = cards.OrderBy(x => r.Next()).ToList();
}
public Card DrawCard(Hand hand)
{
Card drawn = cards[cards.Count - 1];
cards.Remove(drawn);
hand.Cards.Add(drawn);
return drawn;
}
[Serializable]
internal class DeckException : Exception
{
public DeckException()
{
}
public DeckException(string message) : base(message)
{
}
public DeckException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
}
{
public class Hand
{
private List<Card> cards;
public List<Card> Cards
{
get { return cards; }
}
public Hand(int startingHand, deck deck)
{
if (deck == null)
MessageBox.Show("Deck Unavailable");
else if (deck.Cards.Count == 0)
MessageBox.Show("No More Cards to Show");
else
{
cards = new List<Card>();
for (int i = 0; i < startingHand; i++)
{
deck.DrawCard(this);
}
}
}
public void AddValue (Card drw, ref int curScore)
{
if (drw.Value == CardValue.Ace)
{
if (curScore <= 10)
{
curScore += 11;
}
else
{
curScore += 1;
}
}
else if (drw.Value == CardValue.Jack || drw.Value == CardValue.Queen || drw.Value == CardValue.King)
{
curScore += 10;
}
else
{
curScore += (int)drw.Value;
}
}
}
}
// This is where I would enter the methods to run them in my windows forms
{
public partial class P1 : Form
{
private readonly int StartingHand = 2;
private readonly int MaxCards = 5;
PictureBox p;
PictureBox q;
deck deck;
Hand player;
Hand computer;
int computerSum;
int playerSum;
public P1()
{
InitializeComponent();
}
private void splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
{
}
private void P1_Load(object sender, EventArgs e)
{
}
private void resetGameToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void clearTableToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void requestScoreToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void BtnStick_Click(object sender, EventArgs e)
{
}
private void BtnTwist_Click(object sender, EventArgs e)
{
}
}
}
In your post you ask how to add all the methods from other classes into the class where the blackjack game will be played.
Basically, when you declare an instance of something like the Deck class in your MainForm then all of its members have been "added" (in a manner of speaking) because you can access them using the member property that you declared. So that's the first thing we'll do in the MainForm. I will also mention that sometimes there are static or const members and these don't require an instance to use them, rather you would use the class name instead. You'll see examples of this in the MainForm constructor like Card.Spades.
Here's a small snippet of a working sample you can clone here that shows how the classes would be called from the main form using static methods and instances to shuffle and deal five cards to two players:
Set up the UI card "table":
public partial class MainForm : Form
{
// Make instance of the card deck using the `Deck` class
Deck DeckInstance = new Deck();
public MainForm()
{
InitializeComponent();
Text = "Card Game";
tableLayoutCards.Font = new Font("Sergoe UI Symbol", 9);
// Static or const members of a class do not require an
// instance. Use the class name to reference these members.
labelHandA1.Text = $"10 {Card.Spades}";
labelHandA2.Text = $"J {Card.Spades}";
labelHandA3.Text = $"Q {Card.Spades}";
labelHandA4.Text = $"K {Card.Spades}";
labelHandA5.Text = $"A {Card.Spades}";
labelHandB1.Text = $"10 {Card.Hearts}";
labelHandB2.Text = $"J {Card.Hearts}";
labelHandB3.Text = $"Q {Card.Hearts}";
labelHandB4.Text = $"K {Card.Hearts}";
labelHandB5.Text = $"A {Card.Hearts}";
buttonDeal.Click += dealTheCards;
}
Deal the cards by dequeuing them from a "deck" instance.
private async void dealTheCards(object sender, EventArgs e)
{
buttonDeal.Refresh(); UseWaitCursor = true;
// When a non-UI task might take some time, run it on a Task.
await DeckInstance.Shuffle();
// Now we need the instance of the Desk to get the
// cards one-by-one so use the property we declared.
setCard(labelHandA1, DeckInstance.Dequeue());
setCard(labelHandA2, DeckInstance.Dequeue());
setCard(labelHandA3, DeckInstance.Dequeue());
setCard(labelHandA4, DeckInstance.Dequeue());
setCard(labelHandA5, DeckInstance.Dequeue());
setCard(labelHandB1, DeckInstance.Dequeue());
setCard(labelHandB2, DeckInstance.Dequeue());
setCard(labelHandB3, DeckInstance.Dequeue());
setCard(labelHandB4, DeckInstance.Dequeue());
setCard(labelHandB5, DeckInstance.Dequeue());
UseWaitCursor = false;
// Dum hack to make sure the cursor redraws.
Cursor.Position = Point.Add(Cursor.Position, new Size(1,1));
}
Assign a card to the UI element that displays it.
private void setCard(Label label, Card card)
{
label.Text = card.ToString();
switch (card.CardSuit)
{
case CardSuit.Hearts:
case CardSuit.Diamonds:
label.ForeColor = Color.Red;
break;
case CardSuit.Spades:
case CardSuit.Clubs:
label.ForeColor = Color.Black;
break;
}
}
}
Showing too much code here might distract from the actual question, but you might want to clone the full code and set breakpoints to see how it works. (It's not a Blackjack game - I'll leave that to you so I don't take away your fun!).
Uses the following simplified classes:
Card
public class Card
{
// https://office-watch.com/2021/playing-card-suits-%E2%99%A0%E2%99%A5%E2%99%A6%E2%99%A3-in-word-excel-powerpoint-and-outlook/#:~:text=Insert%20%7C%20Symbols%20%7C%20Symbol%20and%20look,into%20the%20character%20code%20box.
public const string Hearts = "\u2665";
public const string Spades = "\u2660";
public const string Clubs = "\u2663";
public const string Diamonds = "\u2666";
public CardValue CardValue { get; set; }
public CardSuit CardSuit { get; set; }
public override string ToString()
{
string value, suit = null;
switch (CardValue)
{
case CardValue.Ace: value = "A"; break;
case CardValue.Jack: value = "J"; break;
case CardValue.Queen: value = "Q"; break;
case CardValue.King: value = "K"; break;
default: value = $"{(int)CardValue}"; break;
}
switch (CardSuit)
{
case CardSuit.Hearts: suit = Hearts; break;
case CardSuit.Spades: suit = Spades; break;
case CardSuit.Clubs: suit = Clubs; break;
case CardSuit.Diamonds: suit = Diamonds ; break;
}
return $"{value} {suit}";
}
}
Deck
public class Deck : Queue<Card>
{
// Instantiate Random ONE time (not EVERY time).
private readonly Random _rando = new Random();
private readonly Card[] _unshuffled;
public Deck()
{
List<Card> tmp = new List<Card>();
foreach(CardValue value in Enum.GetValues(typeof(CardValue)))
{
foreach (CardSuit suit in Enum.GetValues(typeof(CardSuit)))
{
tmp.Add(new Card { CardValue = value, CardSuit = suit });
}
}
_unshuffled = tmp.ToArray();
}
public async Task Shuffle()
{
Clear();
List<int> sequence = Enumerable.Range(0, 52).ToList();
while (sequence.Count != 0)
{
// Choose a unique card index from the sequence at
// random based on the number of ints that remain.
int randomIndexInSequence = _rando.Next(0, sequence.Count());
int cardNumberOutOfOf52 = sequence[randomIndexInSequence];
Enqueue(_unshuffled[cardNumberOutOfOf52]);
sequence.RemoveAt(randomIndexInSequence);
}
// Spin a wait cursor as a visual indicator that "something is happening".
await Task.Delay(TimeSpan.FromMilliseconds(500));
}
public Card GetNext() => Dequeue();
}
Enums
public enum CardValue
{
Ace = 1,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
}
public enum CardSuit
{
Hearts,
Spades,
Clubs,
Diamonds,
}
Please go through the following code which is an oversimplification of the code I have.
I need to know how once the timer is elapsed, how to return control to the main user control class, preferably to the same case within the switch statement.
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
//this is where I need to notify the main class that timer has expired and go to case 2
}
}
}
You can achieve the behavior that you want with events:
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public ucClass()
{
// Listen to event from timer
secObj.TimerExpired += (sender, args) =>
{
A = args.Count;
execute();
};
}
public void execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
public event EventHandler<TimerExpiredEventArgs> TimerExpired;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
// Send event with count
TimerExpired?.Invoke(this, new TimerExpiredEventArgs
{
Count = actualCount
});
}
}
}
public class TimerExpiredEventArgs
{
public int Count { get; set; }
}
I would recommend looking into the following;
The MVVM pattern
This will allow you to seperate the UI logic (passing around labels etc) and the control logic (timers etc).
Reactive Extensions (https://github.com/dotnet/reactive)
This would allow for a very simple timer:
Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(count => {
labelTimer.Text = count.ToString();
if (count > actualCount) {
A = args.Count;
execute();
}
});
I'm new OOP student, I wrote simple clock program on Xamarin studio with C#. The format of clock is 00:00:00. It should be count up and work as a clock.
However, there must be some problems thus my clock can be draw on screen but doesn't "tick".
using SwinGameSDK;
namespace MyGame
{
public class Clock
{
private Counter counter = new Counter();
private int _seconds;
private int _minutes;
private int _hours;
public Clock ()
{
_seconds = counter.SecondsCounter;
_minutes = counter.MinutesCounter;
_hours = counter.HoursCounter;
}
public int Seconds {
get {
return _seconds;
}
set {
_seconds = value;
}
}
public int Minutes {
get {
return _minutes;
}
set {
_minutes = value;
}
}
public int Hours {
get {
return _hours;
}
set {
_hours = value;
}
}
public void DrawClock ()
{
DrawHours ();
SwinGame.DrawText (":", Color.Black, "Arial", 80, 360, 200);
DrawMinutes ();
SwinGame.DrawText (":", Color.Black, "Arial", 80, 520, 200);
DrawSeconds ();
}
public void DrawHours ()
{
SwinGame.DrawText (Hours.ToString ("D2"), Color.Black, "Arial", 80, 250, 208);
}
public void DrawMinutes ()
{
SwinGame.DrawText (Minutes.ToString ("D2"), Color.Black, "Arial", 80, 410, 208);
}
public void DrawSeconds ()
{
SwinGame.DrawText (Seconds.ToString ("D2"), Color.Black, "Arial", 80, 560, 208);
}
public void UpdateClock ()
{
counter.UpdateCounter ();
}
public void ResetClock ()
{
counter.Reset ();
}
public void SetClock ()
{
counter.SetTimer ();
}
}
}
using System.Timers;
namespace MyGame
{
public class Counter
{
private int _hoursCounter;
private int _minutesCounter;
private int _secondsCounter;
public Counter ()
{
_hoursCounter = 0;
_minutesCounter = 0;
_secondsCounter = 0;
}
public int HoursCounter {
get {
return _hoursCounter;
}
set {
_hoursCounter = value;
}
}
public int MinutesCounter {
get {
return _minutesCounter;
}
set {
_minutesCounter = value;
}
}
public int SecondsCounter {
get {
return _secondsCounter;
}
set {
_secondsCounter = value;
}
}
Timer timer = new Timer ();
public void SetTimer ()
{
timer.Interval = 1000;
timer.Elapsed += (sender, e) => UpdateCounter ();
}
public void UpdateCounter ()
{
timer.Start ();
SecondsCounter += 1;
if (SecondsCounter == 60) {
SecondsCounter = 0;
MinutesCounter += 1;
}
if (MinutesCounter == 60) {
MinutesCounter = 0;
HoursCounter += 1;
}
if (HoursCounter == 24) {
HoursCounter = 0;
MinutesCounter = 0;
SecondsCounter = 0;
}
}
public void Reset ()
{
HoursCounter = 0;
MinutesCounter = 0;
SecondsCounter = 0;
timer.Close ();
}
}
}
using SwinGameSDK;
namespace MyGame
{
public class GameMain
{
public static void Main ()
{
var myClock = new Clock ();
//Open the game window
SwinGame.OpenGraphicsWindow ("GameMain", 800, 600);
SwinGame.ShowSwinGameSplashScreen ();
//Run the game loop
while (false == SwinGame.WindowCloseRequested ()) {
//Fetch the next batch of UI interaction
SwinGame.ProcessEvents ();
//Clear the screen and draw the framerate
SwinGame.ClearScreen (Color.White);
SwinGame.DrawFramerate (0, 0);
myClock.DrawClock ();
myClock.SetClock ();
if (SwinGame.MouseClicked (MouseButton.LeftButton)) {
myClock.UpdateClock ();
}
if (SwinGame.MouseClicked (MouseButton.RightButton)) {
myClock.ResetClock ();
}
//Draw onto the screen
SwinGame.RefreshScreen (60);
}
}
}
}
The reason your clock is not ticking because you are continuously resetting it's interval using myClock.SetClock() method. This method should be only called only once outside the while loop in main method. Try following main method;
public static void Main ()
{
var myClock = new Clock ();
//Open the game window
SwinGame.OpenGraphicsWindow ("GameMain", 800, 600);
SwinGame.ShowSwinGameSplashScreen ();
myClock.SetClock (); //Set clock should be called from here.
//Run the game loop
while (false == SwinGame.WindowCloseRequested ()) {
//Fetch the next batch of UI interaction
SwinGame.ProcessEvents ();
//Clear the screen and draw the framerate
SwinGame.ClearScreen (Color.White);
SwinGame.DrawFramerate (0, 0);
myClock.DrawClock ();
if (SwinGame.MouseClicked (MouseButton.LeftButton)) {
myClock.UpdateClock ();
}
if (SwinGame.MouseClicked (MouseButton.RightButton)) {
myClock.ResetClock ();
}
//Draw onto the screen
SwinGame.RefreshScreen (60);
}
}
And SetTimer should be as follows
public void SetTimer ()
{
timer.Interval = 1000;
timer.Elapsed += (sender, e) => UpdateCounter ();
timer.Start ();
}
It seems like you dont even start the timer.
instead of calling timer.Start (); in UpdateCounter (), start the timer after timer.Elapsed += (sender, e) => UpdateCounter ();.
you should also keep your variables together.
private int _hoursCounter;
private int _minutesCounter;
private int _secondsCounter;
Timer timer;
and initialize the timer in the constructor:
..
_secondsCounter = 0;
timer = new Timer();
I've looked through this over and over again, I can't seem to figure out what the issue is. After looking it up some common issue where just people added extra braces or just forgetting one but I've looked through it and cant seem to find where I messed up. What is causing this error and why is it happening? It's showing the errors on lines 120 and 105.
using UnityEngine;
using Rocket.Core.Plugins;
using Rocket.Core.Logging;
using Rocket.Unturned.Events;
using Rocket.Unturned.Player;
using System.Collections.Generic;
using Rocket.Unturned;
using System;
using System.Timers;
namespace VipTeleport
{
public class VipTeleport : RocketPlugin
{
public static VipTeleport Instance;
public Vector3 DeathPos;
public UnturnedPlayer movePlayer;
public bool canTeleport = false;
public int timerT = 0;
public List<string> players = new List<string>();
public List<PlayerFinder> playerVars = new List<PlayerFinder>();
public PlayerFinder playerInfo;
public string steamId;
public int[] playerTimer = new int[24];
public int[] playerSteamID = new int[24];
public bool[] playersCanTeleport = new bool[24];
public int index;
protected override void Load()
{
VipTeleport.Instance = this;
//Just console logs for the plugin in RocketApi on unturneds server console
Logger.LogWarning("##################################");
Logger.LogWarning("#Vip Teleport Loaded Sucessfully!#");
Logger.LogWarning("##################################");
Logger.LogWarning("# Version V.1.0 #");
Logger.LogWarning("##################################");
}
protected override void Unload()
{
}
private void FixedUpdate()
{
U.Events.OnPlayerConnected += (UnturnedPlayer player) =>
{
int addTo = Convert.ToInt32(player.CSteamID);
foreach (int f in playerSteamID)
{
if (f == 0)
{
playerSteamID[f] = addTo;
foreach (int i in playerTimer)
{
playerTimer[f] = 0;
break;
}
foreach (bool t in playersCanTeleport)
{
playersCanTeleport[f] = false;
}
break;
}
}
};
//Listener for player Death
UnturnedPlayerEvents.OnPlayerDead += (UnturnedPlayer player, Vector3 Vector3) =>
{
int localSteamID = Convert.ToInt32(player.CSteamID);
foreach (int i in playerSteamID)
{
if (i == localSteamID)
{
index = i;
playerTimer[index] = 120;
break;
}
}
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(playerTimeVars);
aTimer.Interval = playerTimer[index];
aTimer.Enabled = true;
if ((playerTimer[index] <= 120) && (playerInfo.timerT > 0))
{
playerInfo.canTeleport = true;
}
else
{
playerInfo.canTeleport = false;
playerInfo.timerT = 0;
}
};
U.Events.OnPlayerDisconnected += (UnturnedPlayer player) =>
{
};
public int indexHolder(int i)
{
return i;
}
public void playerTimeVars(object source, ElapsedEventArgs e)
{
int localIndex = indexHolder(index);
playerTimer[localIndex] = 0;
}
}
}
}
Your last two methods need to be below a curly brace, currently they are inside the FixedUpdate() method.
private void FixedUpdate()
{
...
U.Events.OnPlayerDisconnected += (UnturnedPlayer player) =>
{
};
}
public int indexHolder(int i)
{
return i;
}
public void playerTimeVars(object source, ElapsedEventArgs e)
{
int localIndex = indexHolder(index);
playerTimer[localIndex] = 0;
}
Your FixedUpdate() method hasn't got enough brackets.
The methods public int indexHolder(int i), public void playerTimeVars(object source, ElapsedEventArgs e) are placed inside private void FixedUpdate() method which is the source of this error. Place them outside FixedUpdate and it should fix the error
I'm creating an Windowns phone 8 app(c#), its a countdown interval timer, so there is prepare time(10 sec), work time(20 sec), rest time(10 sec). I have these variables
`TimeSpan prepInterval = new TimeSpan(0, 0, 0, 10);
TimeSpan workInterval = new TimeSpan(0, 0, 0, 20);
TimeSpan restInterval = new TimeSpan(0, 0, 0, 10);`
I can't wrap my head around having them implementing them one after another when they hit 0. So when prepare time is done, the work timer is to start and when thats finised, the rest timer is to start.
If you would like to have some more broken down logic in all of this, maybe you can create some classes based on a simple interface, like the following:
interface ITimerAction
{
int Seconds { get; set; }
bool Started { get; }
bool Completed { get; }
void OnStart();
void OnComplete();
}
interface ITimerActionList
{
void Add(ITimerAction action);
void Work();
event EventHandler OnCompletedEvent;
}
This would then allow you to create an abstract TimerAction class, and TimerActionList
abstract class TimerAction : ITimerAction
{
public virtual int Seconds
{
get;
set;
}
public virtual bool Completed
{
get;
protected set;
}
public virtual bool Started
{
get;
protected set;
}
public abstract void OnStart();
public abstract void OnComplete();
}
class TimerActionList : ITimerActionList
{
public event EventHandler OnCompletedEvent;
private readonly IList<ITimerAction> actions = new List<ITimerAction>();
private bool working = false;
private Thread myThread;
public void Add(ITimerAction action)
{
if (working)
{
throw new InvalidOperationException("Cannot add new timers when work is already in progress");
}
actions.Add(action);
}
protected virtual void DoWork()
{
working = true;
int currentStep = 0, maxSteps = actions.Count;
while (currentStep < maxSteps)
{
ITimerAction action = actions[currentStep];
if (!action.Started)
{
action.OnStart();
}
if (action.Completed)
{
currentStep++;
continue;
}
if (action.Seconds == 0)
{
action.OnComplete();
continue;
}
action.Seconds--;
Thread.Sleep(1000);
}
Completed();
}
public void Work()
{
if (working)
{
throw new InvalidOperationException("Already running!");
}
working = true;
myThread = new Thread(DoWork);
myThread.Start();
}
protected virtual void Completed()
{
myThread = null;
working = false;
actions.Clear();
var local = OnCompletedEvent;
if (local != null)
{
local.Invoke(this, EventArgs.Empty);
}
}
}
You could then write the classes that inherit from the TimerAction class, that could handle an action before and after the timer ran through :)
class PrepareTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Preparing");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Prepare ready");
Completed = true;
}
}
class WorkTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Working");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Work ready");
Completed = true;
}
}
class CoolDownTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Cooling down");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Cooldown ready");
Completed = true;
}
}
And then you could test the code as such
static void Main(string[] args)
{
bool done = false;
ITimerActionList mylist = new TimerActionList();
mylist.Add(new PrepareTimer { Seconds = 1 });
mylist.Add(new WorkTimer { Seconds = 2 });
mylist.Add(new CoolDownTimer { Seconds = 1 });
mylist.OnCompletedEvent += (sender, e) =>
{
done = true;
};
mylist.Work();
while (!done)
{
// timer is running
}
Console.WriteLine("Done!");
}
(Console program, but i guess that also goes to demonstrate?)
Here's an example based on deathismyfriend's and Hans Passant's suggestions:
var start = new DateTime();
var stage = 0;
var timer = new System.Timers.Timer(100);
timer.Elapsed += (s, e) =>
{
var elapsed = DateTime.Now - start;
int duration = stage == 1 ? 20 : 10;
if (elapsed.TotalSeconds > duration)
{
start = DateTime.Now;
stage++;
if (stage > 2)
timer.Stop();
}
};
start = DateTime.Now;
stage = 0;
timer.Start();