Controlling menu with the arrow keys and enter
Asked Answered
M

1

10

I was trying to create an RPG. I have a problem with the menu where I can choose a class. I was trying to create an menu where you can control the directions with the arrow keys to the specific class which then get highlighted with the foreground color red, like in a real game when you want to choose something you just use the arrow keys and the thing you are on gets highlighted.

My problem is I can't specify the location of the arrow keys when I press the arrow key. I can only go to the first location and another problem is when I highlight the rpg class to show the user where he is, all rpg classes get the foreground color. I used Console.Read to separate them but now I always have to press Enter to change the color.

Here is the code. I think after you opened the code u will understand my problem.

Best regards Csharpnoob61.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Enter_Eingabe
{
    class Program
    {
        static void Main(string[] args)
        {
            //ints
            int char_HP_Current = 20;
            int char_HP_Full = 100;

            double char_Exp_Current = 10;
            double char_Exp_Full = 100;
            int char_Level_Current = 1;

            int GameOver = 0;
            int char_Move_Left_Right = 0;
            int char_Move_Up_Down = 8;

            int Error = 0;

            int Resting_Time = 0;

            int Attack_Bonus = 0;
            int Speech_Bonus = 0;
            int Sneak_Bonus = 0;
            int Armor_Bonus = 0;
            int Casting_Bonus = 0;


            //Strings

            string char_Name = "";
            string Current_Command;
            string char_Status = "";
            string char_Class;

            string test;

            Console.Clear();




            Console.SetCursorPosition(0, 8);




            do
            {
                string text = "Guardian";
                Console.SetCursorPosition(15, 8);
                Console.WriteLine(text);

                Console.SetCursorPosition(45, 8);
                Console.WriteLine("Paladin");

                Console.SetCursorPosition(30, 8);
                Console.WriteLine("Outlaw");

                ConsoleKeyInfo KeyInfo;
                KeyInfo = Console.ReadKey(true);
                switch (KeyInfo.Key)
                {
                    //Player Controlls


                    case ConsoleKey.RightArrow:
                        Console.SetCursorPosition(0, 8);
                        if (char_Move_Left_Right < 78)
                        {

                            char_Move_Left_Right+=14;
                            Console.SetCursorPosition(char_Move_Left_Right, char_Move_Up_Down);
                            Console.WriteLine("_");
                            Console.SetCursorPosition(char_Move_Left_Right - 1, char_Move_Up_Down);
                            Console.ForegroundColor = ConsoleColor.Black;
                            Console.WriteLine("_");
                            Console.ForegroundColor = ConsoleColor.White;


                        if (char_Move_Left_Right == 14)
                        {
                                if (char_Move_Up_Down == 8)
                                {                                    
                                    Console.ForegroundColor = ConsoleColor.Red;
                                    Console.SetCursorPosition(15, 8);
                                    Console.WriteLine(text);
                                    Console.Read();                                 
                                }
                                Console.ForegroundColor = ConsoleColor.White;
                            }

                        }
                        if (char_Move_Left_Right == 29)
                        {
                            if (char_Move_Up_Down == 8)
                            {
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.SetCursorPosition(30,8);
                                Console.WriteLine("Outlaw");
                                Console.Read();
                            }
                            Console.ForegroundColor = ConsoleColor.White;
                        }
                        if (char_Move_Left_Right == 44)
                        {
                            if (char_Move_Up_Down == 8)
                            {
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.SetCursorPosition(45, 8);
                                Console.WriteLine("Paladin");
                                Console.ReadLine();
                            }
                            Console.ForegroundColor = ConsoleColor.White;
                        }



                        break;
                    case ConsoleKey.LeftArrow:
                        if (char_Move_Left_Right > 1)
                        {
                            char_Move_Left_Right--;
                            Console.SetCursorPosition(char_Move_Left_Right, char_Move_Up_Down);
                            Console.WriteLine("_");
                            Console.SetCursorPosition(char_Move_Left_Right + 1, char_Move_Up_Down);
                            Console.ForegroundColor = ConsoleColor.Black;
                            Console.WriteLine("_");
                            Console.ForegroundColor = ConsoleColor.White;
                        }
                        else { }
                        break;

                    case ConsoleKey.UpArrow:
                        if (char_Move_Up_Down > 3)
                        {
                            char_Move_Up_Down--;
                            Console.SetCursorPosition(char_Move_Left_Right, char_Move_Up_Down);
                            Console.WriteLine("_");
                            Console.SetCursorPosition(char_Move_Left_Right, char_Move_Up_Down + 1);
                            Console.ForegroundColor = ConsoleColor.Black;
                            Console.WriteLine("_");
                            Console.ForegroundColor = ConsoleColor.White;
                        }
                        else { }
                        break;
                    case ConsoleKey.DownArrow:
                        if (char_Move_Up_Down < 21)
                        {
                            char_Move_Up_Down++;
                            Console.SetCursorPosition(char_Move_Left_Right, char_Move_Up_Down);
                            Console.WriteLine("_");
                            Console.SetCursorPosition(char_Move_Left_Right, char_Move_Up_Down - 1);
                            Console.ForegroundColor = ConsoleColor.Black;
                            Console.WriteLine("_");
                            Console.ForegroundColor = ConsoleColor.White;
                        }
                        else { }
                        break;
                } 
            }while (Error == 0);
        }
    }
}
Mathamathe answered 24/10, 2017 at 10:28 Comment(1)
This looks like it's not going to be very reusable and (as you have already encountered) a very error prone way of doing that. I'll take a look if I find something but I recommend you try and put that in a function so you can use it multiple times.Eonism
E
15

Instead of writing every combination by hand, here is what I would do: Use a helper class for common tasks like these kind of multiple-choice actions, pass a set of options and wait for the user to make a selection.

public class ConsoleHelper
{
    public static int MultipleChoice(bool canCancel, params string[] options)
    {
        const int startX = 15;
        const int startY = 8;
        const int optionsPerLine = 3;
        const int spacingPerLine = 14;

        int currentSelection = 0;

        ConsoleKey key;

        Console.CursorVisible = false;

        do
        {
            Console.Clear();

            for (int i = 0; i < options.Length; i++)
            {
                Console.SetCursorPosition(startX + (i % optionsPerLine) * spacingPerLine, startY + i / optionsPerLine);

                if(i == currentSelection)
                    Console.ForegroundColor = ConsoleColor.Red;

                Console.Write(options[i]);

                Console.ResetColor();
            }

            key = Console.ReadKey(true).Key;

            switch (key)
            {
                case ConsoleKey.LeftArrow:
                {
                    if (currentSelection % optionsPerLine > 0)
                        currentSelection--;
                    break;
                }
                case ConsoleKey.RightArrow:
                {
                    if (currentSelection % optionsPerLine < optionsPerLine - 1)
                        currentSelection++;
                    break;
                }
                case ConsoleKey.UpArrow:
                {
                    if (currentSelection >= optionsPerLine)
                        currentSelection -= optionsPerLine;
                    break;
                }
                case ConsoleKey.DownArrow:
                {
                    if (currentSelection + optionsPerLine < options.Length)
                        currentSelection += optionsPerLine;
                    break;
                }
                case ConsoleKey.Escape:
                {
                    if (canCancel)
                        return -1;
                    break;
                }
            }
        } while (key != ConsoleKey.Enter);

        Console.CursorVisible = true;

        return currentSelection;
    }
}

The one above for example can be used like this:

int selectedClass = ConsoleHelper.MultipleChoice(true, "Warrior", "Bard", "Mage", "Archer", 
    "Thief", "Assassin", "Cleric", "Paladin", "etc.");

selectedClass will simply be the index of the selected option when the function returns (or -1 if the user pressed escape). You might want to add additional parameters like a banner text ("Select class") or formatting options.

Should look something like this:

Console output

You can of course add additional marks like _these_ or > those < to further highlight the current selection.

Eonism answered 24/10, 2017 at 11:31 Comment(9)
and remember about cancelling (like pressing Esc) if none of your options is "Back": case(ConsoleKey.Escape) return -1;Scouring
Good idea, I'll add that.Eonism
You guys are Legends Thank you so much i hope i can code that good somedayMathamathe
@Mathamathe No problem. If you like the answer please upvote and accept it to mark this question as answered (top left of the answer).Eonism
I upvoted it but because of my low Reputation it won't be displayed. Where did you learn to program like that ?Mathamathe
@Mathamathe Years of experience. Programming is one of those things where theory can only show you the way - getting better comes with making mistakes and learning how to do it better the next time :)Eonism
Any tips on implementing this in Java? Im having some trouble finding the equivalent of SetCursorPosition().Labyrinthine
@NoamSuissa In Java it seems to be a control code: #1001835Eonism
@ManfredRadlwimmer I also found a great Java library that contains very similar methods to the Console ones used here: github.com/mabe02/lanternaLabyrinthine

© 2022 - 2024 — McMap. All rights reserved.