我如何使用香草JS通过键盘输入进行精灵更改 [英] How do i Make a sprite change with keyboard input i'm using vanilla JS

查看:35
本文介绍了我如何使用香草JS通过键盘输入进行精灵更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此我一直在测试HTML画布.我试图让精灵更改键盘输入.

 <!DOCTYPE html>< html lang ="zh-CN">< head>< meta charset ="UTF-8">< meta name ="viewport" content ="width = device-width,initial-scale = 1.0">< title>文档</title></head><身体>< canvas id ='Game'width ='200'height ='200'style ='border:2px solid#000000;'></canvas>< script>window.onload = function(){var Game = document.getElementById('Game');var context = Game.getContext('2d')var room = new Image();var lx = 0;var ly = 0;var li = 0;var lo = 0;var lwidth = 100;var lheight = 100;room.onload = function(){context.drawImage(room,lx,ly,lwidth,lheight,li,lo,200,200);}room.src ='https://i.ibb.co/D7fL7yN/Room.png';var sprite = new Image();var cx = 0;var cy = 125;var sy = 0;var sx = 0;var swidth = 35;var sheight = 34;sprite.onload = function(){context.drawImage(sprite,sx,sy,swidth,sheight,cx,cy,50,50);}sprite.src ='https://i.ibb.co/7VhjqPr/John-Sheet.png';}</script></body></html>  

我一直在寻找如何使用键盘输入来更改SX,以便让我的角色更改精灵.你能帮助我吗?一个代码示例将是最好的!

解决方案

跟踪键盘状态.

您可以创建一个保存键盘状态的对象,特别是您希望对其进行反应的键.使用 " keydown" " keyup" KeyboardEvent 将键盘状态更新为事件发生了.使用KeyboardEvent属性代码来锻炼哪个键是变化.请勿使用 keyCode ,因为它已经贬值了非标准

您还希望防止按键的默认行为.例如,防止箭头键滚动页面.这是通过调用事件

然后在游戏中,您只需要检查键盘状态

  if(keys.ArrowRight){moveRight()}如果(keys.ArrowLeft){moveLeft()}//等等 

在下面的演示中,按键绑定到游戏动作,这意味着使用的按键和数量与动作无关.还可以通过配置进行设置,以便可以在不更改游戏代码的情况下更改键绑定.您还可以像示例一样绑定其他输入

动画

要设置动画,您应该使用计时器函数 requestAnimationFrame ,因为它是为提供最佳动画效果而专门设计的.它将调用您的渲染函数,您可以将渲染函数视为一个循环,即每次您在动画制作中前进时都会调用它.

放在一起

下面的演示使用以上(修改后的)方法获取键盘输入并通过动画帧请求渲染场景.

它还使用了一些技术(简单版本),可以帮助您将游戏变成更好的产品.

  • player 封装为一个对象
  • 通过将当前呈现功能保持在 currentRenderState
  • 中来维持游戏状态
  • 具有 config 的配置,因此所有重要值都放在一个位置,并且可以加载(从JSON文件)以轻松更改游戏,而无需更改代码.
  • 具有可配置的键盘绑定,请注意,一个游戏动作可以绑定多个按键.例如,移动是通过WASD或箭头键进行的.
  • 所有文本都是可配置的(使其独立于语言)
  • 将2D上下文传递给所有渲染代码.
  • 将游戏与渲染分离.这样可以更轻松地将游戏移植到低端或高端设备上,甚至可以将其移动到服务器上,在该服务器上ctx替换为coms并可以广播游戏.游戏不仅仅改变其渲染方式

  var currentRenderState = getFocus;//当前的游戏状态const config = {玩家:{开始:{x:100,y:100},速度:2imageURL:"https://i.stack.imgur.com/C7qq2.png?s=64&g=1",},按键:{//将按键代码链接到游戏动作上:["ArrowUp","KeyW"],下:["ArrowDown","KeyS"],左:["ArrowLeft","KeyA"],右:["ArrowRight","KeyD"],},touchableTime:140,//以毫秒为单位.设置为0或删除以停用文本: {focus:单击画布以获取焦点",loading:片刻仍在加载媒体!",指示:使用箭头键或WASD移动",}};requestAnimationFrame(mainLoop);//请求第一帧const ctx = gameCanvas.getContext("2d");const w = gameCanvas.width,h = gameCanvas.height;const player = {图片:(()=> {const img =新图片;img.src = config.player.imageURL;img.addEventListener("load",()=> player.size = img.width,{一次:true});返回img;})(),x:config.player.start.x,y:config.player.start.y,大小:0,速度:config.player.speed,方向:0,更新() {var oldX = this.x,oldY = this.y;如果(actions.left){this.x-= this.speed}如果(actions.right){this.x + = this.speed}如果(actions.up){this.y-= this.speed}如果(actions.down){this.y + = this.speed}如果(this.x< 0){this.x = 0}否则if(this.x> w-this.size){this.x = w-this.size}如果(this.y< 0){this.y = 0}否则if(this.y> h-this.size){this.y = h-this.size}const mx = this.x-oldX,my = this.y-oldY;if(mx!== 0 || my!== 0){this.direction = Math.atan2(my,mx)}},draw(ctx){如果(ctx){ctx.setTransform(1,0,0,1,this.x + this.size/2,this.y + this.size/2);ctx.rotate(this.direction + Math.PI/2);//当图像指向上方时旋转90度ctx.drawImage(this.image,-this.size/2,-this.size/2,this.size,this.size);}}}函数drawText(ctx,文本,大小,颜色){如果(ctx){ctx.fillStyle =颜色;ctx.font = size +"px Arial";ctx.textAlign =中心";ctx.fillText(text,w/2,h *(1/4));}}函数getFocus(ctx){drawText(ctx,config.text.focus,24,黑色");}函数drawScene(ctx){如果(!player.size === 0){drawText(ctx,config.text.loading,16,蓝色")actions.hasInput = false;//确保准备好指令后} 别的 {如果(!actions.hasInput){drawText(ctx,config.text.instruct,16,"blue")}player.update();player.draw(ctx);}}函数mainLoop(){ctx.setTransform(1、0、0、1、0、0);ctx.clearRect(0,0,w,h);currentRenderState(ctx);requestAnimationFrame(mainLoop);//请求下一帧}//键保存每个已命名键的动作名称.例如向上动作ArrowUp:向上",KeyW:向上",const键= Object.entries(config.keys).reduce((keys,[action,codes])=>code.reduce((keys,code)=>(keys [code] = action,keys),keys),{});//按下键时将动作设置为true.注意操作的第一向上键将取消操作const操作= Object.keys(config.keys).reduce((actions,action)=>(actions [action] = false,actions,{});addEventListener("keydown",keyEvent);addEventListener("keyup",keyEvent);函数keyEvent(event){如果(keys [event.code]!==未定义){actions [keys [event.code]] = event.type ==="keydown";event.preventDefault();actions.hasInput = true;}}如果(config.touchableTime){const actionTimers = {};touchable.addEventListener("click",(e)=> {如果(e.target.dataset.action){actions [e.target.dataset.action] = true;clearTimeout(actionTimers [e.target.dataset.action]);actionTimers [e.target.dataset.action] = setTimeout(()=> actions [e.target.dataset.action] = false,config.touchableTime);actions.hasInput = true;如果(currentRenderState!== drawScene){window.focus();currentRenderState = drawScene;}}});} 别的 {touchable.classList.add("hide");}gameCanvas.addEventListener("click",()=> currentRenderState = drawScene,{once:true});  

 画布{边框:1像素纯黑色}#游戏 {宽度:402px;高度:182px;font-size:24px;用户选择:无;}.剩下 {位置:绝对;顶部:160px;左:10px;光标:指针;}.正确的 {位置:绝对;顶部:160px;左:355px;光标:指针;}#touchable span:hover {颜色:红色}.hide {display:none}  

 < div id ="game">< canvas id ="gameCanvas" width ="400" height ="180"></canvas>< div id ="touchable">< div class ="left">< span data-action ="up">&#x25B2;</span>< span data-action ="down">&#x25BC;</span></div>< div class ="right">< span data-action ="left">&#x25C4;</span>< span data-action ="right">&#x25BA;</span></div></div></div>  

so ive been testing out HTML canvas. im trying to get a sprite to change on keyboard input.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <canvas id='Game' width='200' height='200' style='border: 2px solid #000000;'></canvas>
  <script>
    window.onload = function(){
      var Game = document.getElementById('Game');
      var context = Game.getContext('2d')
      var room = new Image();
      var lx = 0;
      var ly = 0;
      var li = 0;
      var lo = 0;
      var lwidth = 100;
      var lheight = 100;
      room.onload = function(){
        context.drawImage(room,lx,ly,lwidth,lheight,li,lo,200,200);
      }
      room.src = 'https://i.ibb.co/D7fL7yN/Room.png';
      var sprite = new Image();
      var cx = 0;
      var cy = 125;
      var sy = 0;
      var sx = 0;
      var swidth = 35;
      var sheight = 34;
      sprite.onload = function(){
        context.drawImage(sprite,sx,sy,swidth,sheight,cx,cy,50,50);
        }
        sprite.src = 'https://i.ibb.co/7VhjqPr/John-Sheet.png';
    }
 
  </script>
</body>
</html>

ive been searching on how to change the SX with Keyboard input so my character changes sprites. can you help me? a code example would be best!

解决方案

Tracking keyboard state.

You can create an object that hold the state of the keyboard, specifically the keys you are interested in reacting to. Use the "keydown" and "keyup" KeyboardEvent to update the keyboard state as the events fire. Use the KeyboardEvent property code to workout which key is changing. DO NOT use keyCode as that has depreciated and is Non Standard

You also want to prevent the default behaviour of keys. Eg prevent arrow keys scrolling the page. This is done by calling the event preventDefault function

const keys = {
    ArrowRight: false,
    ArrowLeft: false,
    ArrowUp: false,
    ArrowDown: false,
}
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
function keyEvent(event) {
    if (keys[event.code] !== undefined) {
        keys[event.code] = event.type === "keydown";
        event.preventDefault();
    }
}

Then in the game you need only check the keyboard state

if (keys.ArrowRight) { moveRight() }
if (keys.ArrowLeft) { moveLeft() }
// and so on

In the demo below the keys are binded to game actions, meaning that what and how many keys are used are independent of the action. The are also set via configuration, so that key binding can be changed without changing game code. You can also bind other inputs as in example

Animation

To animate you should use the timer function requestAnimationFrame as it is specifically designed to give the best animation results. It will call your rendering function, you can consider the rendering function like a loop, that is call every time you step forward in animation time.

Putting it together

The demo below use the above (modified) methods to get keyboard input and render the scene via animation frame requests.

It also uses some techniques (simple versions of) that help make your game a better product.

  • Encapsulates the player as an object
  • Maintains game state by holding the current rendering function in currentRenderState
  • Has configuration config so all important values are in one place, and could be loaded (from JSON file) to easily change the game without changing code.
  • Has configurable keyboard binding, Note more than one key can be bound to a game action. In example movement is via WASD or arrow keys.
  • All text is configurable (making it language independent)
  • Passes the 2D context to all rendering code.
  • Separates the game from the rendering. This makes it easier to port the game to low end or high end devices or even move it to a server where ctx is replaced with coms and the game can be broadcast . The game does not change only how it is rendered

var currentRenderState = getFocus; // current game state
const config = {
    player: {
        start: {x: 100, y:100},
        speed: 2,
        imageURL: "https://i.stack.imgur.com/C7qq2.png?s=64&g=1",
    },
    keys: { // link key code to game action
        up: ["ArrowUp", "KeyW"],
        down: ["ArrowDown", "KeyS"],
        left: ["ArrowLeft", "KeyA"],
        right: ["ArrowRight", "KeyD"],
    },
    touchableTime: 140, // in ms. Set to 0 or remove to deactivate
    text: {
       focus: "Click canvas to get focus",
       loading: "Just a moment still loading media!",
       instruct: "Use arrow keys or WASD to move",
    }
};
    
requestAnimationFrame(mainLoop); // request first frame
const ctx = gameCanvas.getContext("2d");
const w = gameCanvas.width, h = gameCanvas.height;



const player = {
   image: (()=> {
       const img = new Image;
       img.src = config.player.imageURL;
       img.addEventListener("load", () => player.size = img.width, {once: true});
       return img;
   })(),
   x: config.player.start.x,
   y: config.player.start.y,
   size: 0,
   speed: config.player.speed,
   direction: 0,
   update() {
       var oldX = this.x, oldY = this.y;
       if (actions.left) { this.x -= this.speed }
       if (actions.right) { this.x += this.speed }
       if (actions.up) { this.y -= this.speed }
       if (actions.down) { this.y += this.speed }

       if (this.x < 0) { this.x = 0 }
       else if (this.x > w - this.size) { this.x = w - this.size }
       if (this.y < 0) { this.y = 0 }
       else if (this.y > h - this.size) { this.y = h - this.size }

       const mx = this.x - oldX, my = this.y - oldY;
       if (mx !== 0 || my !== 0) { this.direction = Math.atan2(my, mx) }
   },
   draw(ctx) {
       if (ctx) {
           ctx.setTransform(1, 0, 0, 1, this.x + this.size / 2, this.y + this.size / 2);
           ctx.rotate(this.direction + Math.PI / 2); // rotate 90 deg as image points up
           ctx.drawImage(this.image,-this.size / 2, -this.size / 2, this.size, this.size);
       }
   }
}
function drawText(ctx, text, size, color) {
    if (ctx) {
        ctx.fillStyle = color;
        ctx.font = size + "px Arial";
        ctx.textAlign = "center";
        ctx.fillText(text, w / 2, h * (1/4));
    }
}
function getFocus(ctx) {
    drawText(ctx, config.text.focus, 24, "black");
}
function drawScene(ctx) {
    if (!player.size === 0) { 
        drawText(ctx, config.text.loading, 16, "blue") 
        actions.hasInput = false; // ensure instruction are up when ready
    } else {
        if (!actions.hasInput) { drawText(ctx, config.text.instruct, 16, "blue")    }
        player.update();
        player.draw(ctx);
    }
}
function mainLoop() {
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.clearRect(0, 0, w, h);
    currentRenderState(ctx);
    requestAnimationFrame(mainLoop); // request next frame
}        
// keys holds action name for each named key. eg for up action ArrowUp: "up", KeyW: "up",
const keys = Object.entries(config.keys)
    .reduce((keys, [action,codes]) => 
         codes.reduce((keys, code) => (keys[code] = action, keys), keys), {});
// actions are set true when key down. NOTE first up key for action cancels action
const actions = Object.keys(config.keys)
    .reduce((actions,action) => (actions[action] = false, actions),{});
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
function keyEvent(event) {
    if (keys[event.code] !== undefined) {
        actions[keys[event.code]] = event.type === "keydown";
        event.preventDefault();
        actions.hasInput = true;
    }
}
if (config.touchableTime) {
  const actionTimers = {};
  touchable.addEventListener("click", (e) => {
      if (e.target.dataset.action) {
          actions[e.target.dataset.action] = true;
          clearTimeout(actionTimers[e.target.dataset.action]);
          actionTimers[e.target.dataset.action] = setTimeout(() => actions[e.target.dataset.action] = false, config.touchableTime);
          actions.hasInput=true;
          if (currentRenderState !== drawScene) {
              window.focus();
              currentRenderState = drawScene;
          }
      }
  });
} else {
  touchable.classList.add("hide");
}
 
gameCanvas.addEventListener("click", () => currentRenderState = drawScene, {once: true});

canvas {border: 1px solid black}
#game {
    width:402px;
    height:182px;
    font-size: 24px;
    user-select: none;
}
.left {
    position: absolute;
    top: 160px;
    left: 10px;
    cursor: pointer;
}
.right {
    position: absolute;
    top: 160px;
    left: 355px;
    cursor: pointer;
}
#touchable span:hover {color: red}
.hide { display: none }

<div id="game">
  <canvas id="gameCanvas" width="400" height="180"></canvas>
  <div id="touchable">
     <div class="left">
         <span data-action="up">&#x25B2;</span>
         <span data-action="down">&#x25BC;</span>
     </div>
     <div class="right">
         <span data-action="left">&#x25C4;</span>
         <span data-action="right">&#x25BA;</span>
     </div>
  </div>
</div>

这篇关于我如何使用香草JS通过键盘输入进行精灵更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆