Make two characters move at the same time - c#

I'm trying to make a little game in the Console App and i want an enemy to move at a constantly while moving the player. The code looks like this right now:
public static int y = 5;
public static string player = "O";
public static int enemyX = 10;
static void Main(string[] args)
{
while (true)
{
Console.SetCursorPosition(enemyX, 10);
Console.Write("X");
enemyX = enemyX - 1;
Console.CursorVisible = false;
Console.SetCursorPosition(5, y);
Console.Write(player);
var move = Console.ReadKey(true);
switch (move.Key)
{
case ConsoleKey.W:
y = y - 1;
break;
case ConsoleKey.S:
y = y + 1;
break;
}
if (y <= 0)
{
y = 1;
}
if (y >= 25)
{
y = 24;
}
Console.Clear();
}
}

From what I understand you want the enemy to move regardless of if the player moves or not and to do that you could use Threads
Example:
bool BreakThread = false; //you need this to break the thread loop
Thread enemyThread = new Thread(()=>
{
while(!BreakThread)
{
//do Enemy Actions
}
});
enemyThread.Start();
//then execute your main game loop
but remember to set the BreakThread value to true when ever you
are closing the game.

Related

How do I make my snake in my game to be just one character insted of printing all over the console in c#?

I'm attempting to make a snake game with C# in the console app. I managed to make the player (snake), the grid or area of the playground, the random food spawner, and collisions of the walls of the grid or playground and food, so every time the snake touches the food, it dissapears and spawns in other random location inside of the playground.
Now the next thing to do is to make my snake to be just 1 char, and everytime it eats the food to add 1 more char to it, so it turns into a 2 char snake... and so on, just how the classic snake game works. Right now, the snake is just 1 char, but it prints all over the console when I move it.
How do I do this? I'm kinda stuck and I've read a lot of others people code and explanation, and they talk about FIFO stack, or a queue. Do I need to delete all of my current code of the player (snake) and recreat from scratch using this type of collection? Here is the main code of the player, the other classes are just for the grid or area, console windows resizing and a simple beeping sound whenever the snake eats the food.
I am a complete begginer and this is my first time doing something like this, so if you find a rookie mistake please tell me so I can get better at it. Thank you!
public class Player
{
private Grid grid = new Grid();
private int x = 38;
private int y = 10;
private Random random1 = new Random();
private Random random2 = new Random();
private int foodx = 0;
private int foody = 0;
public void Play()
{
const char toWrite = '*';
Write(toWrite, x, y);
grid.Create();
while (true)
{
foodx = random1.Next(1, 79);
foody = random1.Next(1, 19);
SpawnFood();
while (x != foodx || y != foody)
{
if (Console.KeyAvailable)
{
var command = Console.ReadKey().Key;
switch (command)
{
case ConsoleKey.UpArrow:
if (y > 1)
y--;
break;
case ConsoleKey.DownArrow:
if (y < 19)
y++;
break;
case ConsoleKey.RightArrow:
if (x < 78)
x++;
break;
case ConsoleKey.LeftArrow:
if (x > 1)
x--;
break;
default:
Console.WriteLine("That key is not avilable");
break;
}
Write(toWrite, x, y);
}
}
}
}
public void Write(char toWrite, int x = 0, int y = 0)
{
if (x >= 0 && y >= 0)
{
Console.SetCursorPosition(x, y);
Console.Write('*');
}
}
public void SpawnFood()
{
Console.SetCursorPosition(foodx, foody);
Console.Write('O');
BeepSound.Do();
}
}
}`

Write to console screen without Console.SetCursorPosition(?,?)

Is there a way to write a string in specific coordinates in a console window without using Console.SetCursorPosition(?,?)
General idea of solving this problem:
Compute the current "frame" of your game, which is just lines of text, completely
Clear the console
Print the entire "frame" to the console
Wait for input, modify in-game objects, repeat.
E.g., I wrote the following "console game": The player is a "*", the rest is filled with "-". Window adapts to resizes automatically. Player can move in every direction with arrow keys (left,right,up,down). No error checking done.
It's a basic setup that uses an array of StringBuilder objects to be able to do easy string modification (strings are immutable). Would make sense to write a general DrawTextInFramebuffer(string text, int x, int y, framebuffer) though.
Edit: Also, mandatory video suggestion: https://www.youtube.com/watch?v=KkMZI5Jbf18, Retro-Racing game using the console window and colored blocks in C++, though C# implementation would also be possible.
using System;
using System.Linq;
using System.Text;
namespace StackOverflowTesting
{
class Program
{
/* Player position */
static int PlayerX = 1;
static int PlayerY = 1;
static string ComputeFrameBuffer()
{
//What are the current dimensions of the console window
int consoleWindowHeight = Console.WindowHeight;
int consoleWindowWidth = Console.WindowWidth - 1; //-1 prevents line overflow
//Compute framebuffer line-wise
var lines = new StringBuilder[consoleWindowHeight];
for(int y = 0; y < consoleWindowHeight; y++)
{
//Create the line as a repetition of consoleWindowWidth spaces or other filler.
lines[y] = new StringBuilder(string.Join("", Enumerable.Repeat("-", consoleWindowWidth)));
for (int x = 0; x < consoleWindowWidth; x++)
{
//What do we need to draw at this (x,y) position? is the player here?
if(PlayerX == x && PlayerY == y)
{
//Yes. Use a '*' for the player "sprite"..
lines[y][x] = '*';
}
}
}
//Concatinate all lines
return string.Join("\n", lines.Select(l => l.ToString()));
}
static void Main(string[] args)
{
bool runGame = true;
while (runGame)
{
//Render current frame
string frame = ComputeFrameBuffer();
Console.Clear();
Console.Write(frame);
//Grab next user input
var pressedKey = Console.ReadKey(false);
//Handle stuff
switch (pressedKey.Key)
{
case ConsoleKey.LeftArrow:
PlayerX--;
break;
case ConsoleKey.RightArrow:
PlayerX++;
break;
case ConsoleKey.UpArrow:
PlayerY--; //Coordinate system is upper left = (0,0). Downwards increases Y.
break;
case ConsoleKey.DownArrow:
PlayerY++;
break;
case ConsoleKey.Escape:
runGame = false;
break;
}
//clamp coordinates to be always within bounds
int maxY = Console.WindowHeight;
int maxX = Console.WindowWidth - 1;
if (PlayerX < 0) PlayerX = 0;
if (PlayerX >= maxX) PlayerX = maxX - 1;
if (PlayerY < 0) PlayerY = 0;
if(PlayerY >= maxY) PlayerY = maxY - 1;
}
}
}
}
To control the drawing of the character to within the viewable console box, just replace the switch statement with this one:
switch (pressedKey.Key)
{
case ConsoleKey.LeftArrow:
{
PlayerX--;
if (PlayerX == -1)
PlayerX++;
}
break;
case ConsoleKey.RightArrow:
{
PlayerX++;
if(PlayerX == width-1)
PlayerX--;
}
break;
case ConsoleKey.UpArrow:
{
PlayerY--;
if (PlayerY == -1)
PlayerY++;
}
break;
case ConsoleKey.DownArrow:
{
PlayerY++;
if (PlayerY == height)
PlayerY--;
}
break;
case ConsoleKey.E:
runGame = false;
break;
}

Trying to figure out how to pause and resume in Cocossharp (BouncyGame)

So I'm playing around with the BouncyGame. I made it so that when you start the game you need to press the screen for it to start. I would like to implement this whenever you play a new round as well. I tried to reuse this att the bottom of my code but it made it extremely laggy.
// Register for touch events
var touchListener = new CCEventListenerTouchAllAtOnce();
touchListener.OnTouchesEnded = OnTouchesEnded;
touchListener.OnTouchesMoved = OnTouchesEnded;
AddEventListener(touchListener, this);
}
void OnTouchesEnded(List<CCTouch> touches, CCEvent touchEvent)
{
if (touches.Count > 0)
{
Schedule(RunGameLogic);
scoreLabel.Text = "Score: 0";
paddleSprite.RunAction(new CCMoveTo(.1f, new CCPoint(touches[0].Location.X, paddleSprite.PositionY)));
}
}
I have no idea how to do this, tried for 2 hours with 0 results. Any suggestions are welcome.
Here's the full code.
using System;
using System.Collections.Generic;
using CocosSharp;
using Microsoft.Xna.Framework;
namespace CocosSharpGameTest
{
public class IntroLayer : CCLayerColor
{
// Define a label variable
CCLabel scoreLabel;
CCSprite paddleSprite, ballSprite;
public IntroLayer() : base(CCColor4B.Black)
{
// create and initialize a Label
scoreLabel = new CCLabel("Tap to GO!", "Arial", 80, CCLabelFormat.SystemFont);
// add the label as a child to this Layer
scoreLabel.PositionX = 50;
scoreLabel.PositionY = 1000;
scoreLabel.AnchorPoint = CCPoint.AnchorUpperLeft;
AddChild(scoreLabel);
paddleSprite = new CCSprite("paddle.png");
AddChild(paddleSprite);
ballSprite = new CCSprite("ball.png");
AddChild(ballSprite);
}
protected override void AddedToScene()
{
base.AddedToScene();
// Use the bounds to layout the positioning of our drawable assets
CCRect bounds = VisibleBoundsWorldspace;
// position the label on the center of the screen
paddleSprite.PositionX = 100;
paddleSprite.PositionY = 100;
ballSprite.PositionX = 320;
ballSprite.PositionY = 640;
// Register for touch events
var touchListener = new CCEventListenerTouchAllAtOnce();
touchListener.OnTouchesEnded = OnTouchesEnded;
touchListener.OnTouchesMoved = OnTouchesEnded;
AddEventListener(touchListener, this);
}
void OnTouchesEnded(List<CCTouch> touches, CCEvent touchEvent)
{
if (touches.Count > 0)
{
Schedule(RunGameLogic);
scoreLabel.Text = "Score: 0";
paddleSprite.RunAction(new CCMoveTo(.1f, new CCPoint(touches[0].Location.X, paddleSprite.PositionY)));
}
}
float ballXVelocity;
float ballYVelocity;
// How much to modify the ball's y velocity per second:
const float gravity = 140;
int score = 0;
void RunGameLogic(float frameTimeInSeconds)
{
// This is a linear approximation, so not 100% accurate
ballYVelocity += frameTimeInSeconds * -gravity;
ballSprite.PositionX += ballXVelocity * frameTimeInSeconds;
ballSprite.PositionY += ballYVelocity * frameTimeInSeconds;
bool overlap = ballSprite.BoundingBoxTransformedToParent.IntersectsRect(paddleSprite.BoundingBoxTransformedToParent);
bool movingDown = ballYVelocity < 0;
if (overlap && movingDown)
{
ballYVelocity *= -1;
const float minXVelocity = -300;
const float maxXVelocity = 300;
ballXVelocity = CCRandom.GetRandomFloat(minXVelocity, maxXVelocity);
score++;
scoreLabel.Text = "Score: " + score;
}
float ballRight = ballSprite.BoundingBoxTransformedToParent.MaxX;
float ballLeft = ballSprite.BoundingBoxTransformedToParent.MinX;
float screenRight = VisibleBoundsWorldspace.MaxX;
float screenLeft = VisibleBoundsWorldspace.MinX;
bool shouldReflectXVelocity =
(ballRight > screenRight && ballXVelocity > 0) ||
(ballLeft < screenLeft && ballXVelocity < 0);
if (shouldReflectXVelocity)
{
ballXVelocity *= -1;
}
if (ballSprite.PositionY < VisibleBoundsWorldspace.MinY)
{
ballSprite.PositionX = 320;
ballSprite.PositionY = 640;
ballXVelocity = 0;
ballYVelocity = 0;
ballYVelocity *= -1;
scoreLabel.Text = "Score: 0";
score = 0;
}
}
}
}
Thanks in advance!
Figured it out!
There is an "Unschedule" Method built into Cocossharp.
Ref. https://developer.xamarin.com/api/namespace/CocosSharp/
I just added
Unschedule(RunGameLogic);
at the very en of my RunGameLogic method under
if (ballSprite.PositionY < VisibleBoundsWorldspace.MinY)
So once the ballSprite is out of bounds it will Unschedule what i Scheduled in my OntouchesEnded method. That means the code goes back to listening for touches.
Might have made some errors, but this is as best I could figure it out and it works!

User null input check for some time and thread

public class green : MonoBehaviour
{
private AudioSource source;
public AudioClip sound;
static int result = 0;
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("a");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
Thread.Sleep(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
yield return new WaitForSeconds(3f * 60f);
gm.life -= 1;
Debug.Log("z");
}
public void Update()
{
if (result == 1 && gm.checka == true)
{
Debug.Log("e");
StopCoroutine("RoutineCheckInputAfter3Minutes");
gm.life += 1;
source.Stop();
gm.checka = false;
Debug.Log("j");
}
if (result == 2 && gm.checkb == true)
{
Debug.Log("f");
StopCoroutine("RoutineCheckInputAfter3Minutes");
gm.life += 1;
source.Stop();
gm.checkb = false;
Debug.Log("z");
}
else if (result == 3 && gm.checkc == true)
{
StopCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("g");
gm.life += 1;
source.Stop();
gm.checkc = false;
Debug.Log(gm.life);
}
}
}
There are two problems
I want to make music stop and life variable decrease -1, if the user doesn't push any buttons for 3 minutes. But if the user pushes the right button, life variable will be increased + 1. but I don't know how to get null input from the user for 3 minutes.
If I use while for this program, this shuts down… until life is below 0, I want to repeat music which is played on irregular time.
Edit: Don't use Thread in Unity
How Unity works
Alternative to Thread
Couroutine Example 1
Coroutine Example 2
* To put it simple, Thread.Sleep hangs to Unity and Unity can't operate for the time, and that's why it looks like running slow.
You can use coroutines for this problem.
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
yield return new WaitForSeconds(3f*60f);
gm.life -= 1;
}
void RightButtonClicked()
{
gm.life += 1;
StopCoroutine("RoutineCheckInputAfter3Minutes");
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
Or, you can just turn your a function into a coroutine, if the other code sections work.
void Start()
{
StartCoroutine(a());
}
public IEnumerator a()
{
while (gm.life >= 0)
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
yield return new WaitForSeconds(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
}
}
This is an example usage of coroutine based on your code More than this is out of scope:
A pastebin link to code

How can I run two Thread.sleep In C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm writing a simple console based game. In the game, I have two functions that should move two things - A paddle and a ball.
But when I use two loops that have Thread.sleep, the game doesn't work. How can I use the two loops with Thread.sleep and get it to run properly?
My code:
class Program
{
static void Ball()
{
}
static void Main(string[] args)
{
int x = 10; int y = 10;
int dx = 1; int dy = 1;
ConsoleKeyInfo Exit = new ConsoleKeyInfo();
do
{
Console.SetCursorPosition(x, y);
Console.WriteLine(" ");
x += dx;
y += dy;
Console.SetCursorPosition(x, y);
Console.Write("*");
Thread.sleep(95);
if (x > 77) dx = -dx;
if (x < 2) dx = -dx;
if (y > 22) dy = -dy;
if (y < 2) dy = -dy;
} while (true);
int a = 2;
int b = 23;
int da = 1;
Console.SetCursorPosition(a, b);
Console.Write(" ");
if (Console.KeyAvailable)
{
ConsoleKeyInfo k = Console.ReadKey(true);
if (k.Key == ConsoleKey.LeftArrow) a = a - da;
else if (k.Key == ConsoleKey.RightArrow) a = a + da;
if (a > 78) a = -da;
if (a < 2) a = -da;
Thread.Sleep(200);
}
Console.SetCursorPosition(a, b);
Console.Write("~~~~~~~~~~");
}
}
When I run the example code you provided, the application will run. That is to say, the ball (*) will move around the screen. Are you expecting the ball to move on the screen, and the paddle to be drawn and move when an arrow is pressed? If so, you should look at how you are looping. The issue I see is that you have a loop that draws the ball and your loop will never ends, and therefore your code will not draw the paddle and/or reflect your arrow key changes. Is your expectation also for the Thread.Sleep to pause the loop and allow you to draw/move the paddle?
UPDATE:
namespace ConsoleGame
{
class Ball {
private static Ball _instance;
private int _a = 10, _b = 10;
private int _dx = 1, _dy = 1;
private int _timer = 0;
private int _milliseconds = 1000;
private Ball() { }
public static Ball Instance {
get {
if(_instance == null) {
_instance = new Ball();
}
return _instance;
}
}
/// <summary>
/// Move the ball on screen
/// </summary>
/// <param name="speed">The refresh/draw speed of the screen</param>
public void Move(int speed) {
if (_timer >= _milliseconds) {
// Set the cursor position to the current location of the ball
Console.SetCursorPosition(_a, _b);
// Clear the ball from the screen
Console.WriteLine(" ");
_a += _dx;
_b += _dy;
// Set a new locatio for the ball
Console.SetCursorPosition(_a, _b);
// Draw the new ball location on screen
Console.Write("*");
if (_a > 77) _dx = -_dx;
if (_a < 2) _dx = -_dx;
if (_b > 22) _dy = -_dy;
if (_b < 2) _dy = -_dy;
} else {
_timer = _timer + speed;
}
}
}
class Paddle {
private int _x = 2, _y = 23, _da = 1;
public int x {
get {
if (_x > (Console.BufferWidth - "~~~~~~~~~~".Length)) x = -_da;
if (_x < 2) x = -_da;
if (_x < 0) x = 2;
return _x;
}
set { _x = value; }
}
private static Paddle _instance;
private Paddle() { }
public static Paddle Instance {
get {
if (_instance == null) {
_instance = new Paddle();
}
return _instance;
}
}
/// <summary>
/// Move the Paddle on screen
/// </summary>
/// <param name="direction">Direction to move the paddle (Left = -1, Right = 1, Do Not Move = 0)</param>
public void Move(int direction) {
Console.SetCursorPosition(x, _y);
Console.Write(" ");
x = x - direction;
Console.SetCursorPosition(x, _y);
Console.Write("~~~~~~~~~~");
}
}
class Program {
private static int PaddleDirection = 0;
static void Main(string[] args) {
Thread ConsoleKeyListener = new Thread(new ThreadStart(ListerKeyBoardEvent));
ConsoleKeyListener.Name = "KeyListener";
ConsoleKeyListener.Start();
//ConsoleKeyListener.IsBackground = true;
int speed = 50;
do {
Console.Clear();
Ball.Instance.Move(speed);
Paddle.Instance.Move(PaddleDirection);
PaddleDirection = 0; // You can remove this line to make the paddle loop left/right on the screen after key press.
Thread.Sleep(speed);
} while (true);
}
private static void ListerKeyBoardEvent() {
do {
ConsoleKeyInfo k = Console.ReadKey(true);
if (k.Key == ConsoleKey.LeftArrow) PaddleDirection = 1;
else if (k.Key == ConsoleKey.RightArrow) PaddleDirection = -1;
else PaddleDirection = 0;
Console.ReadKey(false);
} while (true);
}
}
}

Categories

Resources