Forum

How to control simple animations with keyboard input?

20 May 2018 00:16
I've got four doors that need to be controlled by four keys. I've enabled NLA, all doors open/close on first start, but I can't get keyboard input to work no matter what. I've tried to combine js code from the "making a game" example https://www.blend4web.com/en/community/article/38/ along with stuff from the animation user manual https://www.blend4web.com/doc/en/animation.html#animation-control . No examples that I found give me a clear answer on how to do it and I desperately need someone to get me on track.
21 May 2018 01:50
You define keyboard sensors for the four keys (let's say "Key_1" - "Key_4") with m_ctl.create_kb_sensor_manifold(); they all call back your callback function "key_cb", each passing their respective door number (1-4) as a param:
m_ctl.create_kb_sensor_manifold(null, "__key1", m_ctl.CT_SHOT, m_ctl.KEY_1, key_cb, "1")
m_ctl.create_kb_sensor_manifold(null, "__key2", m_ctl.CT_SHOT, m_ctl.KEY_2, key_cb, "2")
m_ctl.create_kb_sensor_manifold(null, "__key3", m_ctl.CT_SHOT, m_ctl.KEY_3, key_cb, "3")
m_ctl.create_kb_sensor_manifold(null, "__key4", m_ctl.CT_SHOT, m_ctl.KEY_4, key_cb, "4")


Whenever a key 1-4 is pressed, the callback function retrieves the door number in the param and plays the animation. That's all. I made an example that controls four doors with keys 1-4 and also opens/closes doors properly. You do this by playing the animation backwards, for which you have to pass a negative speed param in m_anim.set_speed() and set the starting frame to the last frame of the animation in m_anim.set_frame().

Example: Four doors that are controlled by keys

Code of the door.js:
"use strict"

// register the application module
b4w.register("doors_main", function(exports, require) {

// import modules used by the app
var m_app       = require("app");
var m_data      = require("data");
var m_preloader = require("preloader");

var m_anim      = require("animation");
var m_cont      = require("container");
var m_ctl       = require("controls");
var m_scs       = require("scenes");

var _door_state = [0, 0,0,0,0] // 0 = door closed, 1 = door open 

// automatically detect assets path
var APP_ASSETS_PATH = ".";

/**
 * export the method to initialize the app (called at the bottom of this file)
 */
exports.init = function() {
  m_app.init({
    canvas_container_id: "main_canvas_container",
    callback: init_cb,
    show_fps: true,
    console_verbose: true,
    autoresize: true
  });
}

function init_cb(canvas_elem, success) {
  if (!success) {
    console.log("b4w init failure");
    return;
  }
  m_preloader.create_preloader();
  canvas_elem.oncontextmenu = function(e) {
    e.preventDefault();
    e.stopPropagation();
    return false;
  };
  load();
}

function load() {
  m_data.load(APP_ASSETS_PATH + "/doors.json", load_cb, preloader_cb);
}

function preloader_cb(percentage) {
  m_preloader.update_preloader(percentage);
}

function load_cb(data_id, success) {
  if (!success) {
    console.log("b4w load failure");
    return;
  }
  m_app.enable_camera_controls();

  m_ctl.create_kb_sensor_manifold(null, "__key1", m_ctl.CT_SHOT, m_ctl.KEY_1, key_cb, "1") // define KB sensor for Key "1"
  m_ctl.create_kb_sensor_manifold(null, "__key2", m_ctl.CT_SHOT, m_ctl.KEY_2, key_cb, "2") // define KB sensor for Key "2"
  m_ctl.create_kb_sensor_manifold(null, "__key3", m_ctl.CT_SHOT, m_ctl.KEY_3, key_cb, "3") // define KB sensor for Key "3"
  m_ctl.create_kb_sensor_manifold(null, "__key4", m_ctl.CT_SHOT, m_ctl.KEY_4, key_cb, "4") // define KB sensor for Key "4"
}

function key_cb() { // callback will be called when key 1-4 was pressed
  var door_number = arguments[3];                        // get the door number (1-4) from the parameter passed by the sensor
  var d = m_scs.get_object_by_name("door"+door_number);  // get the object reference of the door object
  m_anim.apply(d,"door"+door_number+"Action")            // apply the Blender animation
  m_anim.set_behavior(d, m_anim.AB_FINISH_STOP)          // set the anim behavior: simply stop after playing, don't rewind
  m_anim.set_frame(d,_door_state[door_number]?25:1)      // if doorstate is "closed", set anim to first frame (1), else last frame (25)
  m_anim.set_speed(d,_door_state[door_number]?-1:1)      // if doorstate is "closed", play anim forward (speed=1), else backwards (speed=-1)
  m_anim.play(d,null);                                   // play the animation for object d, pass no callback (null)
  _door_state[door_number] = 1+_door_state[door_number]*-1 // toggle doorstate between 0/1 (i.e. closed/open)
}

});

// import the app module and start the app by calling the init method
b4w.require("doors_main").init();
12 June 2018 17:55
Reply to post of user Blend4Life

Hey, thank you for that! I was able to get it working on my own project.

However, is it possible to get the code to read serial output from an Arduino instead?

I just realized the one I have can't act as a keyboard, but keyboard input was more of a temporary solution anyway. Ideally I would have it read the initial state of a door (ON/OFF) and then play animation based on state changes. But for a start, even getting simple buttons to work would be great.
12 June 2018 20:22
read serial output from an Arduino
Wow dude, I have no clue about Arduino devices. But if the input of an Arduino can be read in a browser through javascript, then you can certainly control the doors (or do just about anything) with that input.
12 June 2018 20:53
Reply to post of user Blend4Life
Wow dude, I have no clue about Arduino devices. But if the input of an Arduino can be read in a browser through javascript, then you can certainly control the doors (or do just about anything) with that input.
It looks like that can be accomplished using Node.js, but I wonder if I can get it to work. https://hackernoon.com/arduino-serial-data-796c4f7d27ce
12 June 2018 21:40
I don't see why it would not work. Looks to me like there's a function that fetches the incoming serial port data:
    port.on('data', function(data) {
        console.log(data);

    });

So there you go. If you can get your project to the point where this function works and actually streams your incoming device data, well, instead of console logging, you just insert your own B4W-related code there, such as calls to m_anim.play() etc. Sky's the limit.
 
Please register or log in to leave a reply.