【问题标题】:Flash As3 key press issueFlash As3 按键问题
【发布时间】:2016-05-03 19:31:13
【问题描述】:

好的,所以我的主要问题是用于闪存的KeyboardEvent 太慢了。可以说我按左箭头。由于某种原因,移动延迟然后移动。当我在做二段跳或根本跳的时候,我不得不按住按钮而不是单按。我的问题是闪光灯有没有办法检测任何键的单次按下以及如何解决 keyCode 的移动延迟?

import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
import flash.events.Event;

//Initialized variables

var theKey:KeyObject = new KeyObject(stage);//Help the stage checks for keypressed objects
var hspeed:Number = 0;// horizontal speed
var vspeed:Number = 0;// vertical speed
var gravity:Number = 2;//Gravity
var friction:Number  = .5;//Friction
var ground:int = 800;//Bottom of the stage
var JumpMax:Number = 0;//Double jump

//All Booleans (Mainly player states)
var aDown:Boolean = false;//Press left key
var dDown:Boolean = false;//Press right key
var Jumped:Boolean = false;//Player in jumping state
var AttackMode:Boolean = false;//Player in attacking state
var CrouchMode:Boolean = false;//Player in crouched state
var RightSide:Boolean = false;//Player hitting right side of block
var LeftSide:Boolean = false;//Player hitting left side of block
var DownSide:Boolean = false;//Player hitting the top of block
var UpSide:Boolean = false;//Player hits bottom of block

ultraDaimyo.gotoAndStop("idleDaimyo");

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyYeet);
function keyYeet(e:KeyboardEvent):void 
{
if(e.keyCode == Keyboard.D)
    {
        dDown = true;

    }
if(e.keyCode == Keyboard.A)
    {
        aDown = true;

    }
if(e.keyCode == Keyboard.C)
  {
    AttackMode = true;

  }
if(e.keyCode == Keyboard.W || Jumped == true)
  {
    Jumped = true;
  }
 }

 stage.addEventListener(KeyboardEvent.KEY_UP, keyNot);
 function keyNot(e:KeyboardEvent):void 
{
if(e.keyCode == Keyboard.D)
 {
    dDown = false; 
 }
if(e.keyCode == Keyboard.A)
 {
    aDown = false; 
 }
if(e.keyCode == Keyboard.C)
 {
    AttackMode = false; 
 }
if(e.keyCode == Keyboard.W)
 {
    Jumped = false; 
 }
 }


 stage.addEventListener(Event.ENTER_FRAME, gameCycle);
 function gameCycle(e:Event):void
{
hspeed *= friction;
ultraDaimyo.x += hspeed;
ultraDaimyo.y += gravity;

if(AttackMode)
      {
        ultraDaimyo.gotoAndStop("attackDaimyo");
        ultraDaimyo.x += 5;
        if(ultraDaimyo.scaleX == -1)
          {
            ultraDaimyo.gotoAndStop("attackDaimyo");
            ultraDaimyo.x -= 10;
          }
      }
if(Jumped == true)
  {
     ultraDaimyo.y -= 30;
     ultraDaimyo.gotoAndStop("jumpDaimyo");
  } 
if(dDown)
  {
     hspeed += 20;
     ultraDaimyo.gotoAndStop("runDaimyo");
     ultraDaimyo.scaleX = 1;
  }
if(aDown)
  {
     hspeed -= 20;
     ultraDaimyo.gotoAndStop("runDaimyo");
     ultraDaimyo.scaleX = -1;
  }
if(!aDown && !dDown && !AttackMode && !Jumped)
  {
    ultraDaimyo.gotoAndStop("idleDaimyo");
  }


if(ultraDaimyo.x - ultraDaimyo.width/2 < 0)//If the player goes past the left side
  {
    ultraDaimyo.x = ultraDaimyo.width/2;
  }
if(ultraDaimyo.x + ultraDaimyo.width/2 > 1400)//If the player goes past right
  {
    ultraDaimyo.x = 1400 - ultraDaimyo.width/2;//Player cant go past
  } 
if(ultraDaimyo.y + ultraDaimyo.height/2 < floor && Jumped)//If we are above the floor
  {
    if(Jumped)
      {
          ultraDaimyo.gotoAndStop("jumpDaimyo");
      }
    gravity++;//Accelerate gravity in the process
  }
if(ultraDaimyo.y + ultraDaimyo.height/2 > floor)
  {
    Jumped = false;//If we are on the floor then we're not jumping
    gravity = 0;//Gravity can no longer be applied
    ultraDaimyo.y = floor - ultraDaimyo.height/2;//Player sits on top of the floor
  }
}

【问题讨论】:

  • 答案是肯定的。如果您想要比这更好的答案,请编辑您的问题并向您显示当前代码,以便有人可以指出您的延迟来自哪里。
  • 更新:我刚刚在这里添加了我的角色 Daimyo 的完整代码。现在问题是键盘事件本身。 keyCode 只是延迟片刻,然后进行移动。另外,我仍然想知道 as3 是否只能检测到按下而不是保持。谢谢!
  • 您所说的“仅按”是什么意思?本质上,KEY_UP 事件相当于一次新闻发布会。您的代码看起来不错,如果我不得不猜测,您的延迟来自您的gotoAndStop,而不是事件本身。尝试在您的按键处理程序 (keyYeet) 中添加一个跟踪语句,看看该跟踪是否会立即触发,而不是您在时间轴上看到的任何内容。
  • 是的,它可以检测短按和长按。为什么你的function keyYeet 中需要if(aDown) 语句和布尔值之类的东西?只要该相关键发送“使用中”信号,ultraDaimyo... 代码就会持续触发。实验并查看...
  • 我的意思是能够检测到一个简单的点击,而不是实际按住它。我在跳跃时遇到问题,因为我实际上必须按住向上键才能真正让玩家处于跳跃状态,直到它到达地面。我只想让 flash 简单地检测一个短暂的点击,然后执行整个跳转过程。

标签: actionscript-3 flash


【解决方案1】:

KeyboardEvent 不会连续触发,因为这样会很难检测到单个击键。

你需要做的是使用KeyboardEvent只改变速度变量,但将速度应用于不同连续Event中的位置变量,即Event.ENTER_FRAME。

我根据您的代码创建了一个示例:

import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
import flash.events.Event;

//Initialized variables
var speedX:Number = 0;

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyYeet);

function keyYeet(e:KeyboardEvent):void
{
    if(e.keyCode == Keyboard.D)
    {
        speedX = 20;
    }

    if(e.keyCode == Keyboard.A)
    {
        speedX = -20;
    }
}

stage.addEventListener(KeyboardEvent.KEY_UP, keyNot);

function keyNot(e:KeyboardEvent):void
{
    if(e.keyCode == Keyboard.D || e.keyCode == Keyboard.A)
    {
        speedX = 0;
    }
}

addEventListener(Event.ENTER_FRAME, gameCycle);

function gameCycle(e:Event):void
{
    ultraDaimyo.x += speedX;
}

这个想法是在按键下降到某个值时设置速度,并在按键恢复时将其设置回0。

速度持续应用于位置。


来自 cmets:

请仔细检查你的第一句话。

果然有错别字,但内容和我想的一样。

结果是连续发射 = 连续移动。

不适合我。对于不同的(键盘)硬件或软件(操作系统、闪存运行时),这可能会有所不同。其他人也有类似的经历,这可以从手头问题的这些副本中看出。

我们不要看显示对象四处移动并比较它们是否连续移动的意见。让我们收集一些可比较的数据。

这是一个小文档类,用于计算 5 次 KEY_DOWN 事件发生之间的延迟。

要使用它,请确保应用程序具有焦点并按下任意按钮,直到跟踪出现在输出面板中。

松开按键会重置数组,并且可以按住另一个按键。

package 
{
    import flash.utils.getTimer;
    import flash.events.KeyboardEvent;
    import flash.display.Sprite;

    public class Main extends Sprite 
    {
        private var oldTime:Number = 0;
        private var deltaTimes:Array = [];

        public function Main() 
        {
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
        }

        private function onKeyDown(e:KeyboardEvent):void
        {
            var currentTime:Number = getTimer();

            // collect 5 time differences between two consecutive occurrences of this event

            if (deltaTimes.length < 5)
            {
                deltaTimes.push(currentTime - oldTime)    
            }
            else
            {
                stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
                trace(deltaTimes);
            }

            oldTime = currentTime;           
        }

        private function onKeyUp(e:KeyboardEvent = null):void
        {
            deltaTimes = [];

            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
        }
    }
}

这是我的结果:

7584,499,49,51,50
2117,500,50,50,50
1786,500,50,50,49
1375,499,48,50,52
1395,500,50,50,50
1385,500,50,50,50
1243,501,47,52,49
2167,501,49,50,50
1587,500,50,50,50
3871,500,50,48,53
2237,500,49,51,49
1715,500,47,53,50

可以观察到三个重要的事情:

  1. 第一个值显然不感兴趣,因为它是时间 在两次按钮按下之间。 (我只是想把这个放在一起 快)
  2. 第二个值大约是 500 毫秒,这意味着在第一个和 事件第二次发生,半秒时间过去了。
  3. 最后3个值大约是50ms,比 500 毫秒。这是只要按键被按下,事件就会持续触发的速率

我在上面的回答中提供的代码解决了这个问题。

【讨论】:

  • 请仔细检查您的第一句话。试试 this code(用一个小的彩色矩形制作 my_mc)。你会看到,只要左键或右键给出“使用中”信号,结果就是连续开火=连续移动。相同的代码检测到单击或长按键...不需要向上键来停止移动(尽管在 Asker 的代码中会影响 ultraDaimyo.scaleX = ... 代码,所以也许他们确实需要一个“向上键”信号来停止恒定缩放)。
  • 嗨,我看了一下。这是好东西。关于你的开场白,虽然我不同意。我说它确实会持续触发,否则很难检测到长按。要检测单次击球,用户只需在 k/board 上按一下即可触发事件一次。它也有连续射击的能力。我的意思是就人类感知而言。这回答了 Asker 对单击与长按的担忧。我确认两者都可以。我认为他们的问题是延迟时间很长(想象一下,在您按下跳转以获得代码反应后等待 2 或 3 秒的延迟)。
  • 我还没有检查这些链接,但这很奇怪,因为我从键盘上得到了几乎即时的反应(对我的眼睛)。您确认它稳定在 50ms。那是 1/20 秒 秒。你不认为这种每秒发射20次的能力可以算作“连续”吗?那么为什么告诉我它没有,然后向我展示它可以的证据呢?再读一遍提问者的问题(尤其是跳跃延迟问题),你就会明白我为什么告诉他们我做了什么。否则我确实学到了一些新东西(我不知道大约 50 毫秒,所以它让我想到在我的一个应用程序中修复一个“东西”)。 +1 给出
  • @VC.One:我展示了问题所要求的不连续性的证据:“由于某种原因,移动延迟然后移动。”
猜你喜欢
  • 1970-01-01
  • 2014-03-19
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多