I'm programming a tetris game. So far I have implemented a timer with a very short interval of around 50 ms. Every tick the current falling tetromino gets moved one position in the game matrix downwards. Then the game checks if there is a collision, if so the tetromino gets marked as "landed" and new tetromino is spawned.
No I have the problem that I want to give the player the chance to move the tetromino to the left or right for let's say 0.5 seconds after it landed to have the possibility to move the tetromino underneath an overhanging already landed tetromino.
But with my current code I have the problem that as soon as there is a collision detected the timer continues and spawns the next tetromino. My idea now was to try to implement a second timer that gets activated for 0.5 seconds everytime a collision is detected to allow for additional keyboard input bevore the main timer continues. So basically pausing the main timer for 0.5 seconds and allow the program to detect keyboard input during that time and then continue with the main timer.
Everything I tried so far didn't really work. It seems like the first timer always continues running while I have a second timer active.
This is how my first timer looks like:
private void TimerBrick_Tick(object sender, EventArgs e)
{
ResetGameBoard(jaggedTetrisBricks[rnd-1][rotation], _brickX, _brickY, xLengthBrick, yLengthBrick);
_brickX++;
CollisionCheck(jaggedTetrisBricks[rnd - 1][rotation], _brickX, _brickY, xLengthBrick, yLengthBrick);
LineCheck();
Invalidate();
}
Now I somehow need to implement inside my CollisionCheck() method a way to wait for 0.5 seconds before the code continues with LineCheck().
Or is there another way that I'm not seeing right now?
In addition to my previous comment - here is a bit of pseudo-code :
enum GameState
{
Starting,
CreateBrick,
BrickFalling,
MoveSideways
}
private GameState curState = Starting;
private ushort ctSideways;
private void TimerBrick_Tick(object sender, EventArgs e)
{
switch (curState)
{
case Starting:
InitialiseGame();
curState = CreateBrick;
break;
case CreateBrick:
CreateNewBrick();
curState = BrickFalling;
break;
case BrickFalling:
.....
.....
if (CollisionCheck())
{
ctSideways = 0;
curState = MoveSideways;
}
break;
case MoveSideways:
.....
.....
ctSidways++;
if (ctSideways == 10)
curState = CreateBrick;
break;
}
}
Related
I want to make countdown timer that will return value of bool when he is active , so I can check on other script if is active give double points if is not then you need to give normal points..
I want to make it more complicated and I want to add time on timer if the timer is active, if is not then we use default time on countdown...
I don't know how to use courutine specially when I need to add time if the timer is not over..
Lets say like a example:
I pick up power up and timer starts for 5 seconds counting to 0.
If i pick up again powerup and timer is on lets say 3 , Power up need to have now 8 seconds. When powerup is over he must go from 5 seconds when player pick up new one..
Here is my code that doesn't work how I want also my code doesn't have a function to add time to power up when power up is active.. In other words I don't know how i can check if powerup is active and if yes just to add to counter 5 more seconds..
Here is code that doesn't contain adding time it only contains working counter..
void startDoublePoints()
{
StartCoroutine("doublePoints");
Time.timeScale = 1;
}
//Simple courutine
IEnumerator doublePoints()
{
while (true)
{
yield return new WaitForSeconds(1);
timeLeft--;
}
}
I hope someone will explain me more about how I can achieve my goal.. I hope I explained what I need to achieve.. If you do not understand something please ask on comment and I will try to explain it again..
Thank you so much community I don't know how would I learn anything without this great place :)
float powerUpTimer;
bool isDoublePoints = false;
void Update()
{
// Check timer only when Power up time
if(isDoublePoints)
{
// Countdown the timer with update time
powerUpTimer -= Time.deltaTime;
if(powerUpTimer <= 0)
{
// End of power up time
isDoublePoints = false;
powerUpTimer = 0;
}
}
}
// Add any time player picks to timer
public void OnPickPowerUp(float buffTime)
{
isDoublePoints = true;
powerUpTimer += buffTime;
}
I been working on a script for a pause menu and i don't know how to make it stop before start executing the next line
This is the code, i ask for this because execute the "if" multiple times, because detects that i'm still pressing the Cancel button. (I use c# and work on Unity 5)
Thanks
using UnityEngine;
using System.Collections;
public class MenuPausa : MonoBehaviour {
public GameObject menuPausa;
private bool pausaMenu = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Cancel") || pausaMenu == false) {
menuPausa.SetActive (true);
Time.timeScale = 0;
WaitForSeconds(1);
pausaMenu = true;
} else {
menuPausa.SetActive (false);
Time.timeScale = 1;
Invoke("waiting",0.3f);
}
}
}
I would use a coroutine kinda like this:
bool paused = false;
void Update ()
{
if (paused) // exit method if paused
return;
if (Input.GetButtonDown("PauseButton"))
StartCoroutine(OnPause()); // pause the script here
}
// Loops until cancel button pressed
// Sets pause flag
IEnumerator OnPause ()
{
paused = true;
while (paused == true) // infinite loop while paused
{
if (Input.GetButtonDown("Cancel")) // until the cancel button is pressed
{
paused = false;
}
yield return null; // continue processing on next frame, processing will resume in this loop until the "Cancel" button is pressed
}
}
This only "pauses" and resumes this individual script. All the other scripts will continue executing their Update methods. To pause the frame rate independent methods (i.e. physics), set Time.timeScale = 0f when pausing and back to 1f when unpaused. If pausing all the other scripts is desired and they're dependent upon frame rate (i.e. Update methods) then use a global pause flag instead of the local paused variable used in this example and check to see if the flag is set in each Update method, like in this example.
I apologize if I'm misunderstanding this, but it seems to me like you're opening and closing a pause menu using the "Cancel" button, and that your script seems to be immediately closing it after opening it due to the "Cancel" button still being pressed. It also seems to me that this script is intended to be a component of the menu object that is being turned on and off. If that is the case, I would suggest the following:
Have this script be used on an object other than the menu itself (such as a MenuManager object or something - also I would change this script's name to MenuManger to avoid confusing it with the actual menu) that will remain active in the scene. Have a PauseMenu object in the scene that gets assigned to this MenuManager's "menuPausa" property. I would then remove the pausaMenu variable. Also, make sure this script is added as a component to ONLY the one object (the MenuManager), otherwise a second object might update in the same frame and turn the menu right back off.
At the end of the method, put
Thread.Sleep(1000);
It pauses the execution for 1000 miliseconds == 1 second.
Is this simple solution enough or do you need a more complex one with a Timer?
You can use a timer, insert it from the toolbar, change the interval which is in milliseconds, then once thats done use the scripts timer.Start(); and timer.Stop();
thats what i used.
pretty new here...
I am making a program that will allow a user to control a sprite (walking on a surface/jumping/falling - the usual... pretty basic i know)
To make the sprite jump in such a way, so that the human eye can actually see a rise and fall on the form, i need to slow the process by which the program translated the sprite upwards.
I decided to use a timer, not SLEEP because i don't want the whole program to freeze.
Here's what i came up with:
private void jump()
{
global.CharacterY = global.CharacterY - 1;
framer_Tick(null, new EventArgs()); //pause program without freezing
}
private void framer_Tick(object sender, EventArgs e)
{
sprite.Location = new Point(global.CharacterX, global.CharacterY);
}
Called by this:
private void Stage_KeyDown(object sender, KeyEventArgs e)
{
if (global.counter >= 1 & e.KeyCode.ToString() == "D")
{
global.CharacterX = global.CharacterX + 1;
jump();
}
if (e.KeyCode.ToString() == "W")
{
while (global.counter < 50)
{
jump();
global.counter = global.counter + 1;
}
global.counter = 0;
}
if (e.KeyCode.ToString() == "D")
{
global.CharacterX = global.CharacterX + 1;
sprite.Location =
new Point(global.CharacterX, global.CharacterY);
}
if (e.KeyCode.ToString() == "A")
{
global.CharacterX = global.CharacterX - 1;
sprite.Location =
new Point(global.CharacterX, global.CharacterY);
}
}
Now, the timer doesn't seem to have any effect. I assumed that placing the code to translate the sprite inside the timer would make it fire once every time the timer ticked.
- Unfortunately i don't have the experience make the timer pause the program (preferably 30 times a second, at an interval of 33(ish)) -
Simply changing the location of the sprite will not do anything. You have to call Invalidate() on whatever control the sprite is being drawn on to see the effect.
Also, you don't call framer_tick to get the process started. You have to call Start and Stop methods on the timer object. When you call Start, the tick handler will start getting called. When you call Stop, it will stop.
To make all of your animation smooth and logic less problematic your tick timer should be going off all the time because you should be redrawing the screen all the time. With the screen refreshing itself you just change the location of the sprite and the animation will behave as you expect it.
Simply changing the location of the sprite will not do anything. You have to call Invalidate() on whatever control the sprite is being drawn on to see the effect. Also, you don't call framer_tick to get the process started. You have to call start/stop on the timer object. When you call start, the tick handler will start getting called. When you call stop, it will stop. But I agree with #Chris. Your tick timer should be going off all the time because you should be redrawing the screen all the time. After that you just change the location of the sprite and everything will be fine. – Paul Sasik
In my pong game I'm making I have two paddles and a ball. I'm trying to make so when the ball collides with the paddle, an effect/animation is shown. I have a spritehseet and a working animation. I use this to detect when the animation plays (please notice that I havent fixed the position of the effect yet, so it plays on 400, 300 just to see if it works)
public bool BallHitEffect()
{
if (gPaddle.gpRect.Intersects(ball.ballRect))
{
return true;
}
else { return false; }
And in my Draw:
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
if (BallHitEffect())
{
animatedSprite.Draw(spriteBatch, new Vector2(400, 250));
}
}
Now it appears when it collide, but only for a short millisecond, because when the ball leaves the paddle, it disappears. I'm aware that it's coded to only appear when it is colliding with the paddle, but in what way could I possibly make it only disappear only when it's animation ends?
You can easily used elapsed time and some makeshift timers to do this. I assume your spritesheet is a series of frames, and that you already have rendering set up.
You will need some variables to start out:
double frameTimePlayed; //Amount of time (out of animationTime) that the animation has been playing for
bool IsPlaying; //Self-Explanitory
int frameCount; //Frames in your sprite, I'm sure you already handle this in your animation logic, but I just threw it in here
int animationTime = 1000; //For 1 second of animation.
In your update method you need to
Check if the ball is intersecting, and set IsPlaying to true
If the animation IsPlaying, increment the frameTimePlayed by the elapsed time
If the frameTimePlayed is equal to or greater than the animationTime, stop the animation by setting IsPlaying to false
In your draw method you need to
Draw the animation, if IsPlaying
Here is some example code:
protected override void Update(GameTime gameTime)
{
//If it is not already playing and there is collision, start playing
if (!IsPlaying && BallHitEffect)
IsPlaying = true;
//Increment the frameTimePlayed by the time (in milliseconds) since the last frame
if (IsPlaying)
frameTimePlayed += gameTime.ElapsedGameTime.TotalMilliseconds;
//If playing and we have not exceeded the time limit
if (IsPlaying && frameTimePlayed < animationTime)
{
// TODO: Add update logic here, such as animation.Update()
// And increment your frames (Using division to figure out how many frames per second)
}
//If exceeded time, reset variables and stop playing
else if (IsPlaying && frameTimePlayed >= animationTime)
{
frameTimePlayed = 0;
IsPlaying = false;
// TODO: Possibly custom animation.Stop(), depending on your animation class
}
}
And for drawing, pretty easy, just check is IsPlaying and draw if that is the case.
I made sure to comment the code good, so hopefully this will help you understand and work better.
You could also use a double and use TotalSeconds instead of milliseconds if needed, and calculate elapsed time with float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
I have a user control that shows a speed in a dial format (An image).
It has a single method: SetSpeed(int speed);
It then makes the dial move to the desired speed, from the last set speed. It does then in incriments. That is, it moves to the new speed.
Problem is, if the car is going 10km/h, and then goes (very quickly) to 100km/h, it takes the dial maybe 2 seconds to reach that speed... (It's not 100% real time - which is realistic .. it moves to the new speed).
But, if, before the dial gets to 100km/h, the person slows to 50km/h, I need to interupt the movement to 100, and start moving to 50. Regardless of the current position (not speed) of the dial, I need to change the 'target speed'.
My control is using a BackgroundWorker to handle the refreshing, and not lock the UI.
So, my call is very basic from the UI:
dial1.SetSpeed(int.Parse(value));
And then the user control does this:
BackgroundWorker bw = new BackgroundWorker();
public void SetSpeed(int speed)
{
while(bw.IsBusy)
{
Thread.Sleep(50);
}
bw.RunWorkerAsync(speed);
}
And the method that does the work:
private void UpdateSpeed(object sender, DoWorkEventArgs e)
{
var oldSpeed = airSpeed;
var newSpeed = (int) e.Argument;
if(oldSpeed <= newSpeed)
{
for (int i = oldSpeed; i < newSpeed; i++)
{
airSpeed++;
this.Invoke(new MethodInvoker(Refresh));
}
}
else
{
for (int i = oldSpeed; i > newSpeed; i--)
{
airSpeed--;
this.Invoke(new MethodInvoker(Refresh));
}
}
airSpeed = newSpeed;
}
It locks when I send it two values in quick succession...
How do I interrupt the thread, if it's running, and change the value?
(Also, I think my code to change the speed is bad - can that be made neater?)
You do not. You handle it in a proper way, with locks, and checking whether the value needs changing. You do NOT interrupt it.
Basically, you need a lock area between SetSpeed and the Refresh method, so that one blocks the other. Then, when you set speed and the thread is currently in a critical area, it simply waits until the update is finished.
And your UpdateSpeed makes no sense - the change (airspeed-- and airspeed++) should be timer driven... you currently change them in a "arbitrary" speed, depending on processor speed. No timing.