我有一个代码可以让玩家输入他们的名字(是的,老式的) 声明变量:
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;
我在课程的开头将它设为零
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);
}
我想问的是:
如何使该输入字段的活动字段闪烁?
使用当前代码,我只能使所有字段闪烁(使用gameTime.TotalGameTime.Milliseconds % 1000 < 500
作为抽绳)。
我正在使用"_"
填写空格" "
。保存播放器名称数据后,"_"
也会保存在数据库中。当"_"
保存到外部来源时,如何将" "
更改为"_"
?
当玩家尝试在所有字段中保存带有{{1}}字符的玩家名称时,如何向玩家显示警告消息...?
任何人都可以帮忙......?
对不起,如果这很长。 谢谢你
答案 0 :(得分:0)
好了...
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.
}
}
然后,在您的绘制方法中,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;
!
除此之外,我可以告诉你,这是一个非常糟糕的方式来获取输入并建议其他更简单/更好的方法,但这并没有真正回答这个问题,当人们不回答时我也讨厌它问题:))
玩得开心。
答案 1 :(得分:0)
以下是基于输入的输入解决方案,而不是选择字符。
此代码使用本机win32 API来检测击键(包括控制字符)。
代码由gamedev.net用户Promit in this post提供。
在项目中创建一个新类,将其命名为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,重复计数等。您可以使用这些来为程序添加其他逻辑。关于windows如何处理击键on this msdn link(非常易于理解)的有用读物。
如果需要,您还可以在EventInput类上注册KeyPressed和KeyReleased事件。
我测试了我在这里发布的代码,它对我有用!
玩得开心!
修改强>: 如果你想使用Unicode字符(与你的语言相关,即我使用ščćžđ),你需要像这样调用DLLImports:
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
因此,您必须更改所有DllImport调用以包含CharSet = CharSet.Unicode
。
此外,不要忘记扩展spritefont的范围以包含您可能想要显示的其他字符。