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);
}
我想问的是:
如何使该输入字段的活动字段闪烁?使用当前的代码,我只能使所有字段闪烁(使用
gameTime.TotalGameTime.Milliseconds % 1000 < 500
为drawstring)。我用
"_"
来填充空间" "
。当玩家的名字数据被保存时,"_"
也被保存在数据库中。我怎么能使"_"
更改为" "
,当它保存到外部源…?我怎么能显示一个警告消息给玩家,当他们试图保存玩家的名字与
"_"
字符在所有领域…?
有谁能帮忙吗?
很抱歉,如果这很长。谢谢你
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
。
另外,不要忘记扩展你的精灵字体的范围,以包括那些你可能想要显示的其他字符。