XNA播放器输入过程

本文关键字:过程 输入 播放器 XNA | 更新日期: 2023-09-27 18:16:27

我有一个代码,让玩家输入他们的名字,就像这样(是的,它是老式的)声明变量:

bool hiScore = false; 
string[] alphabet = new string[] { "_", "a", "b", "c", "d", "e", "f", "g", "h",
       "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", 
       "x", "y", "z" }; 
int ltrCounter1, ltrCounter2, ltrCounter3, ltrCounter4, ltrCounter5; 
string plyrNamePos1, plyrNamePos2, plyrNamePos3, plyrNamePos4, plyrNamePos5; 
int letterPosition = 1;

我在类开始时将它设为0

ltrCounter1 = 0;
ltrCounter2 = 0; 
ltrCounter3 = 0;
ltrCounter4 = 0;
ltrCounter5 = 0;
plyrNamePos1 = alphabet[0];
plyrNamePos2 = alphabet[0];
plyrNamePos3 = alphabet[0];
plyrNamePos4 = alphabet[0];
plyrNamePos5 = alphabet[0]

和在update()方法中,我放置了这个代码来抓取箭头键,并用它们来改变字母。

keyboardState = Keyboard.GetState();
if (CheckKey(Keys.Up))
{
    hiScoreUp();
}
else if (CheckKey(Keys.Down))
{
    hiScoreDown();
}
if (CheckKey(Keys.Right))
{
    letterPosition++;
    if (letterPosition > 5)
    {
        letterPosition = 5;
    }
}
else if (CheckKey(Keys.Left))
{
    letterPosition--;
    if (letterPosition < 1)
    {
        letterPosition = 1;
    }
}
else if (CheckKey(Keys.Enter))
{
    saveHighScores();
    QuizScreen.score = 100;
    ActionScreen.halaman = 1;
    kembalikemenuutama = true;
}

和这个方法来改变字母

private void hiScoreUp() 
{ 
    switch (letterPosition) 
    { 
        case 1: 
            ltrCounter1++; 
            if (ltrCounter1 > 26) 
            { 
                ltrCounter1 = 0; 
            } 
            plyrNamePos1 = alphabet[ltrCounter1]; 
            break; 
        case 2: 
            ltrCounter2++; 
            if (ltrCounter2 > 26) 
            { 
                ltrCounter2 = 0; 
            } 
            plyrNamePos2 = alphabet[ltrCounter2]; 
            break; 
        case 3: 
            ltrCounter3++; 
            if (ltrCounter3 > 26) 
            { 
                ltrCounter3 = 0; 
            } 
            plyrNamePos3 = alphabet[ltrCounter3]; 
            break; 
        case 4: 
            ltrCounter4++; 
            if (ltrCounter4 > 26) 
            { 
                ltrCounter4 = 0; 
            } 
            plyrNamePos4 = alphabet[ltrCounter4]; 
            break; 
        case 5: 
            ltrCounter5++; 
            if (ltrCounter5 > 26) 
            { 
                ltrCounter5 = 0; 
            } 
            plyrNamePos5 = alphabet[ltrCounter5]; 
            break; 
    } 
} 
private void hiScoreDown() 
{ 
    switch (letterPosition) 
    { 
        case 1: 
            ltrCounter1--; 
            if (ltrCounter1 < 0) 
            { 
                ltrCounter1 = 26; 
            } 
            plyrNamePos1 = alphabet[ltrCounter1]; 
            break; 
        case 2: 
            ltrCounter2--; 
            if (ltrCounter2 < 0) 
            { 
                ltrCounter2 = 26; 
            } 
            plyrNamePos2 = alphabet[ltrCounter2]; 
            break; 
        case 3: 
            ltrCounter3--; 
            if (ltrCounter3 < 0) 
            { 
                ltrCounter3 = 26; 
            } 
            plyrNamePos3 = alphabet[ltrCounter3]; 
            break; 
        case 4: 
            ltrCounter4--; 
            if (ltrCounter4 < 0) 
            { 
                ltrCounter4 = 26; 
            } 
            plyrNamePos4 = alphabet[ltrCounter4]; 
            break; 
        case 5: 
            ltrCounter5--; 
            if (ltrCounter5 < 0) 
            { 
                ltrCounter5 = 26; 
            } 
            plyrNamePos5 = alphabet[ltrCounter5]; 
            break; 
    } 
}

我是这样画的

hiScoreName = plyrNamePos1 + " " + plyrNamePos2 + " " + plyrNamePos3 + " " + 
      plyrNamePos4 + " " + plyrNamePos5;
if (gameTime.TotalGameTime.Milliseconds % 1000 < 500)
{
    spriteBatch.DrawString(spriteFont, hiScoreName, new Vector2(350, 280), 
    Color.Blue);
}

我想问的是:

  1. 如何使该输入字段的活动字段闪烁?使用当前的代码,我只能使所有字段闪烁(使用gameTime.TotalGameTime.Milliseconds % 1000 < 500为drawstring)。

  2. 我用"_"来填充空间" "。当玩家的名字数据被保存时,"_"也被保存在数据库中。我怎么能使"_"更改为" ",当它保存到外部源…?

  3. 我怎么能显示一个警告消息给玩家,当他们试图保存玩家的名字与"_"字符在所有领域…?

有谁能帮忙吗?

很抱歉,如果这很长。谢谢你

XNA播放器输入过程

ok…

1)与显示由所有字符组成的字符串不同,您可以将单个字符相邻地绘制

hiScoreName = plyrNamePos1 + plyrNamePos2 + plyrNamePos3 + plyrNamePos4 + plyrNamePos5;
int characterSpacing = 20; //might be more or less for you
for(int i=1; i<=5; i++){
    if(i==letterposition){
        if(gameTime.TotalGameTime.Miliseconds % 1000 < 500){
            spriteBatch.DrawString(spriteFont, hiScoreName[i-1], new Vector(350 + (i-1)*characterSpacing, 280), Color.Blue);
        }
    }else{
        spriteBatch.DrawString(spriteFont, hiScoreName[i-1], new Vector(350 + (i-1)*characterSpacing, 280), Color.Blue);
    }
}

注意:我只是在这里输入了这段代码,从来没有测试过,所以它可能有一些错误:)

2)您可以使用String.Replace()方法。

String stringToSave = hiScoreName.Replace("_"," ");

3)当你检测到所有的字符都是_时,你应该在你的程序中设置一个标志(比如一个bool变量),表明玩家试图保存为全部_。然后在你的draw方法中,如果设置了这个标志,你可以显示你的消息。当玩家改变角色时,该标志将被重置。

bool _invalidHiScoreName = false; //somewhere outside methods.
void SavePlayerScore(String hiScoreName, int score){
    bool allUnderscore = true;
    foreach(char c in hiScoreName){
        if(c!='_')
            allUnderscore = false;
    }
    if(allUnderscore){
        _invalidHiScoreName = true;
    }else{
        String stringToSave = hiScoreName.Replace("_"," "); //from step 2)
        //your saving logic.
    }
}

然后,在你的draw方法中,在spriteBatch.Begin()spriteBatch.End()之间,你可以输入:

if(_invalidHiScoreName){
    spriteBatch.DrawString(spriteFont, "Hi Score Name must have at least one character!", Vector2.Zero, Color.White); //Might wanna position it.
}

当角色被改变时,不要忘记重置标志_invalidHiScoreName=false; !

除此之外,我可以告诉你,这是一个非常糟糕的输入方式,并建议其他更简单/更好的方法,但这并不能真正回答问题,我也讨厌人们不回答问题:)

玩。

这是一个基于键入而不是选择字符的输入解决方案。

此代码使用本地win32 API来检测按键(包括控制字符)。

代码由gamedev.net用户promise提供。

在项目中创建一个新类,命名为CharEventArgs,并将其中的内容替换为以下内容(来自上面链接的代码):

using System;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
namespace EventInput
{
    public class CharacterEventArgs : EventArgs
    {
        private readonly char character;
        private readonly int lParam;
        public CharacterEventArgs(char character, int lParam)
        {
            this.character = character;
            this.lParam = lParam;
        }
        public char Character
        {
            get { return character; }
        }
        public int Param
        {
            get { return lParam; }
        }
        public int RepeatCount
        {
            get { return lParam & 0xffff; }
        }
        public bool ExtendedKey
        {
            get { return (lParam & (1 << 24)) > 0; }
        }
        public bool AltPressed
        {
            get { return (lParam & (1 << 29)) > 0; }
        }
        public bool PreviousState
        {
            get { return (lParam & (1 << 30)) > 0; }
        }
        public bool TransitionState
        {
            get { return (lParam & (1 << 31)) > 0; }
        }
    }
    public class KeyEventArgs : EventArgs
    {
        private Keys keyCode;
        public KeyEventArgs(Keys keyCode)
        {
            this.keyCode = keyCode;
        }
        public Keys KeyCode
        {
            get { return keyCode; }
        }
    }
    public delegate void CharEnteredHandler(object sender, CharacterEventArgs e);
    public delegate void KeyEventHandler(object sender, KeyEventArgs e);
    public static class EventInput
    {
        /// <summary>
        /// Event raised when a character has been entered.
        /// </summary>
        public static event CharEnteredHandler CharEntered;
        /// <summary>
        /// Event raised when a key has been pressed down. May fire multiple times due to keyboard repeat.
        /// </summary>
        public static event KeyEventHandler KeyDown;
        /// <summary>
        /// Event raised when a key has been released.
        /// </summary>
        public static event KeyEventHandler KeyUp;
        delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
        static bool initialized;
        static IntPtr prevWndProc;
        static WndProc hookProcDelegate;
        static IntPtr hIMC;
        //various Win32 constants that we need
        const int GWL_WNDPROC = -4;
        const int WM_KEYDOWN = 0x100;
        const int WM_KEYUP = 0x101;
        const int WM_CHAR = 0x102;
        const int WM_IME_SETCONTEXT = 0x0281;
        const int WM_INPUTLANGCHANGE = 0x51;
        const int WM_GETDLGCODE = 0x87;
        const int WM_IME_COMPOSITION = 0x10f;
        const int DLGC_WANTALLKEYS = 4;
        //Win32 functions that we're using
        [DllImport("Imm32.dll")]
        static extern IntPtr ImmGetContext(IntPtr hWnd);
        [DllImport("Imm32.dll")]
        static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
        [DllImport("user32.dll")]
        static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
        /// <summary>
        /// Initialize the TextInput with the given GameWindow.
        /// </summary>
        /// <param name="window">The XNA window to which text input should be linked.</param>
        public static void Initialize(GameWindow window)
        {
            if (initialized)
                throw new InvalidOperationException("TextInput.Initialize can only be called once!");
            hookProcDelegate = new WndProc(HookProc);
            prevWndProc = (IntPtr)SetWindowLong(window.Handle, GWL_WNDPROC,
                (int)Marshal.GetFunctionPointerForDelegate(hookProcDelegate));
            hIMC = ImmGetContext(window.Handle);
            initialized = true;
        }
        static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
        {
            IntPtr returnCode = CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
            switch (msg)
            {
                case WM_GETDLGCODE:
                    returnCode = (IntPtr)(returnCode.ToInt32() | DLGC_WANTALLKEYS);
                    break;
                case WM_KEYDOWN:
                    if (KeyDown != null)
                        KeyDown(null, new KeyEventArgs((Keys)wParam));
                    break;
                case WM_KEYUP:
                    if (KeyUp != null)
                        KeyUp(null, new KeyEventArgs((Keys)wParam));
                    break;
                case WM_CHAR:
                    if (CharEntered != null)
                        CharEntered(null, new CharacterEventArgs((char)wParam, lParam.ToInt32()));
                    break;
                case WM_IME_SETCONTEXT:
                    if (wParam.ToInt32() == 1)
                        ImmAssociateContext(hWnd, hIMC);
                    break;
                case WM_INPUTLANGCHANGE:
                    ImmAssociateContext(hWnd, hIMC);
                    returnCode = (IntPtr)1;
                    break;
            }
            return returnCode;
        }
    }
}

在你的Game1.cs(或任何你决定命名它)中,把using EventInput;放在最上面。

在Initialize方法中添加以下内容:

EventInput.EventInput.Initialize(this.Window);
EventInput.EventInput.CharEntered += new CharEnteredHandler(EventInput_CharEntered);

在你的Game1.cs(还是你给它起的名字)中,添加相关的处理程序:

    void EventInput_CharEntered(object sender, CharacterEventArgs e)
    {
        if (char.IsControl(e.Character))
        {
            switch (e.Character)
            {
                case ''b':
                    if (hiScoreName.Length > 0)
                    {
                        hiScoreName = hiScoreName.Substring(0, hiScoreName.Length - 1);
                    }
                    break;
                case ''r':
                    //enter
                    break;
            }
        }
        else
        {
            hiScoreName += e.Character;
        }
    }

最后,在你的Draw()方法中,使用类似的代码来绘制字符串:

        spriteBatch.Begin();
        spriteBatch.DrawString(spriteFont, hiScoreName, new Vector2(20f, 20f), Color.Black);
        spriteBatch.End();

概要:

这几乎使这个主题中的其他内容无效(包括您的代码,以及我在另一个答案中发布的所有内容),因为它使用不同的方式从用户获取输入。

一旦你把代码粘贴到CharEventArgs.cs中,你可以安全地关闭它,再也不打开它,它会做它应该做的事情。

处理输入的主要点是您的事件处理程序EventInput_CharEntered,您检查按下的字符,并对其进行操作。您应该使用这个方法,添加您自己的代码,以便您可以在一个情况下将它用于hiScoreName输入,并在另一个地方将它用于其他文本输入。

你可以看到,在事件处理程序中,我注释了//输入,所以你可以说,在那里放一个函数调用来处理保存hiScoreName !

另外,请注意CharacterEventArgs e 包含关于附加修饰符的信息,例如Alt、repeat count等。您可以使用它们向程序添加额外的逻辑。关于windows如何在此msdn链接上处理击键的有用阅读(非常容易理解)。

如果你需要的话,你也可以在EventInput类中注册KeyPressed和KeyReleased事件。

我测试了我张贴在这里的代码,它适用于我!

玩得开心!

编辑:如果您想使用Unicode字符(与您的语言相关,例如,我使用ščćžđ),您需要像这样调用DLLImports:

[DllImport("user32.dll", CharSet = CharSet.Unicode)]

所以你必须改变所有的DllImport调用来包含CharSet = CharSet.Unicode

另外,不要忘记扩展你的精灵字体的范围,以包括那些你可能想要显示的其他字符。