#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# Use arrow keys to "pull" object, translate keypresses to changes in X, Y, and Z rotation

edited May 2018

I have a few questions: Which order is best for XYZ rotation, and how do I transform keypresses to "pull" an object (or some objects) down, up, left, or right? I tried making a perspective vector, but I had no idea what I was doing, and failed. Could someone perhaps attach some code of "pulling" a cube in certain directions by pressing the arrow keys? This would be incredibly useful for a 3-D Minecraft clone, rather than a 2-D version I decided to develop instead.

Tagged:

While writing the main post, I realized that you should rotate the camera in the opposite direction. Not only does it work just as well, it makes it easier to rotate multiple objects, and enables panning and zooming.

• Solved?

• do you use peasy cam?

• here is a version with wasd / pl / space bar

without peasy cam

``````float rotationX;
float rotationY;
float rotationZ;

float translatex=0;
float translatey=0;
float translatez=0;

float z = 1.0;

int objectNumber = 0;

PShape s;

void setup() {

size(1200, 900, P3D);
background(0);
sphereDetail(32);

s = createShape();
s.beginShape();
s.fill(255, 0, 0);
s.stroke(177);
s.vertex(100, 0, -100);
s.vertex(-60, 0, 200);
s.vertex(-50, 60, -30);
s.vertex(110, 160, 40);
s.endShape(CLOSE);
}

void draw() {
background(0);
lights();

showObject();

fill(255); // white
text ("Use wasd and pl (space bar to toggle object)",
19, 19);

if (keyPressed)
keyPressed_ForContinuusKeyinput();
}

// -----------------------------------------------------------

void showObject() {

// show object

pushMatrix();

fill(255, 0, 0); // red
translate(width/3, height/2, 0);
translate(translatex-300, translatey-300, translatez-300);
rotateZ(rotationZ);
rotateY(rotationY);
rotateX(rotationX);
scale(z);

if (objectNumber==0) {
stroke(111);
box(100);
} else if (objectNumber==1) {
shape(s, 0, 0);
//rect(-33, -33, 66, 66);
} else if (objectNumber==2) {
noStroke();
sphere(90);
}//else

popMatrix();
}

// -----------------------------------------------------------

void keyPressed_ForContinuusKeyinput() {
// keyPressed for registering a key throughout

float speed = 3.9;

switch(key) {

case 'a':
translatex-=speed;
break;

case 'd':
translatex+=speed;
break;

case 'w':
translatey-=speed;
break;

case 's':
translatey+=speed;
break;

case 'p':
translatez-=speed;
break;

case 'l':
translatez+=speed;
break;
}//switch
}//func

// ----------------------------

void keyPressed() {

// keyPressed for registering a single key only

switch(key) {
case ' ':
objectNumber++;
if (objectNumber>2)
objectNumber=0;
key=0;
break;
}//switch
//
}//func
//
``````
• new version with full peasy cam support, only 4 lines more ; you can rotate scene with mouse now (you need to install library: Menu | Import library | Add library)

``````// with peasy : http://mrfeinberg.com/peasycam/

import peasy.PeasyCam; // new

PeasyCam cam;

float rotationX;
float rotationY;
float rotationZ;

float translatex=0;
float translatey=0;
float translatez=0;

float z = 1.0;

int objectNumber = 0;

PShape s;

void setup() {

size(1200, 900, P3D);
background(0);
sphereDetail(32);

cam = new PeasyCam(this, 400); // new

s = createShape();
s.beginShape();
s.fill(255, 0, 0);
s.stroke(177);
s.vertex(100, 0, -100);
s.vertex(-60, 0, 200);
s.vertex(-50, 60, -30);
s.vertex(110, 160, 40);
s.endShape(CLOSE);
}

void draw() {
background(0);
lights();

showObject();

cam.beginHUD();
fill(255); // white
text ("Use wasd and pl (space bar to toggle object)",
19, 19);

if (keyPressed)
keyPressed_ForContinuusKeyinput();

cam.endHUD();
}

// -----------------------------------------------------------

void showObject() {

// show object

pushMatrix();

fill(255, 0, 0); // red
translate(width/3, height/2, 0);
translate(translatex-300, translatey-300, translatez-300);
rotateZ(rotationZ);
rotateY(rotationY);
rotateX(rotationX);
scale(z);

if (objectNumber==0) {
stroke(111);
box(100);
} else if (objectNumber==1) {
shape(s, 0, 0);
//rect(-33, -33, 66, 66);
} else if (objectNumber==2) {
noStroke();
sphere(90);
}//else

popMatrix();
}

// -----------------------------------------------------------

void keyPressed_ForContinuusKeyinput() {
// keyPressed for registering a key throughout

float speed = 3.9;

switch(key) {

case 'a':
translatex-=speed;
break;

case 'd':
translatex+=speed;
break;

case 'w':
translatey-=speed;
break;

case 's':
translatey+=speed;
break;

case 'p':
translatez-=speed;
break;

case 'l':
translatez+=speed;
break;
}//switch
}//func

// ----------------------------

void keyPressed() {

// keyPressed for registering a single key only

switch(key) {
case ' ':
objectNumber++;
if (objectNumber>2)
objectNumber=0;
key=0;
break;
}//switch
//
}//func
//
``````
• edited April 2018 Answer ✓

in this version you have the current box/sphere/folded triangle shape that you can move. With return you can add it to the list of all objects.

This version makes use of a class "Box3D" and of objects that are stored in an `ArrayList` boxes. For class and objects see tutorial:

https://www.processing.org/tutorials/objects/

• you need to install library peasy cam: Menu | Import library | Add library.

Chrisir ;-)

``````// https : // forum.processing.org/two/discussion/27564/use-arrow-keys-to-pull-object-translate-keypresses-to-changes-in-x-y-and-z-rotation#latest
// with peasy : http://mrfeinberg.com/peasycam/

import peasy.PeasyCam;

PeasyCam cam;

// ArrayLists for the class
ArrayList<Box3D> boxes = new ArrayList();

// this is a very important size: size boxes
float sizeBox = 70.0;

float rotationX;
float rotationY;
float rotationZ;

float translatex=-sizeBox;
float translatey=-sizeBox;
float translatez=0;

float z = 1.0;

int objectNumber = 0;

// folded triangle
PShape s;

float offsetZ=400;

color colCurrent=color(0, 0, 255);

boolean showHelpText=true;

void setup() {

size(1200, 900, P3D);
background(0);
sphereDetail(32);

cam = new PeasyCam(this, 400); // new

s = createShape();
s.beginShape();
s.fill(255, 0, 0);
s.stroke(177);
s.vertex(100, 0, -100);
s.vertex(-60, 0, 200);
s.vertex(-50, 60, -30);
s.vertex(110, 160, 40);
s.scale(0.4);
s.endShape(CLOSE);
}

void draw() {
background(0);
lights();

for (Box3D b : boxes ) {
b.display();
}

showObject();

cam.beginHUD();
if (showHelpText) {
fill(255); // white
text ("Use PeasyCam. Use wasd and pl; r/g/b for colors, space bar to toggle object, RETURN to enter object to list.\n\n"
+"Use x to switch this text on and off. \n"
+"Use Mousewheel to zoom, double click to reset view. The box you move has a white outline. An item that has been added to the list is marked with a gray box.\n"
+"On adding to the list the placing box moves two units left. \n"
+"Current: "
+translatex
+", "
+translatey
+", "
+translatez,
19, 19);
}

if (keyPressed)
keyPressed_ForContinuusKeyinput();

cam.endHUD();
}

// -----------------------------------------------------------

void showObject() {

// show object

pushMatrix();

fill(colCurrent); // color
//translate(width/3, height/2, 0);
translate(translatex, translatey, translatez);
//rotateZ(rotationZ);
//rotateY(rotationY);
//rotateX(rotationX);

stroke(255);

if (objectNumber==0) {
//stroke(111);
box(sizeBox);
} else if (objectNumber==1) {
s.setFill(colCurrent);
shape(s, 0, 0);
} else if (objectNumber==2) {
//noStroke();
sphere(sizeBox);
}//else

popMatrix();
}

// -----------------------------------------------------------

void keyPressed_ForContinuusKeyinput() {
// keyPressed for registering a key throughout

float speed = 3.9;

switch(key) {

case 'a':
translatex-=speed;
break;

case 'd':
translatex+=speed;
break;

case 'w':
translatey-=speed;
break;

case 's':
translatey+=speed;
break;

// --

case 'p':
translatez-=speed;
break;

case 'l':
translatez+=speed;
break;

// -----

//
}//switch
//
}//func

// ----------------------------

void keyPressed() {

// keyPressed for registering a single key only

switch(key) {
case ' ':
objectNumber++;
if (objectNumber>2)
objectNumber=0;
key=0;
break;

case RETURN:
case ENTER:
Box3D newBox = new Box3D (
translatex,
translatey,
translatez,
rotationY,
objectNumber,
colCurrent
);
translatex-=sizeBox*2;
break;

// ---
//colors

case 'r':
colCurrent=color(255, 0, 0);
break;

case 'b':
colCurrent=color(0, 0, 255);
break;

case 'g':
colCurrent=color(0, 255, 0);
break;

// --

case 'x':
showHelpText = !showHelpText;
break;
}//switch
//
} //func

//=============================================================

class Box3D {

float x=mouseX, y=410, z=mouseY;

float offsetX=0;
float offsetZ2=0;

float rotateY=0;
color colBox = color(255, 0, 0);

// type
final int boxTypeUndefined = -1;
final int boxType0   = 0;
final int boxType1   = 1;
final int boxType2   = 2;
// more needed !!!!! ????
int type = boxTypeUndefined;

// constr - full
Box3D(float x_,
float y_,
float z_,
float rotateY_,
int type_,
color col1_) {
//

x=x_;
y=y_;
z=z_;

rotateY= rotateY_;
type=type_;

colBox=col1_;
} // constr 2

void display() {
pushMatrix();

translate(x, y, z);

fill(colBox);
noStroke();

// depending on the current buttons tag
//
switch (type) {

case boxTypeUndefined:
// undefined
break;

case boxType0:
stroke(111);
box(sizeBox);
break;

case boxType1:
s.setFill(colBox);
shape(s, 0, 0);
break;

case boxType2:
noStroke();
sphere(sizeBox);
break;

default:
// error
break;
}//switch

if (showHelpText) {
translate(sizeBox/2, -sizeBox/2, sizeBox/2);

fill(111);
stroke(0);
box(sizeBox/6);
}

popMatrix();
} // method

String toString() {
return
str(x) +","+
str(y) +","+
str(z) +","+
str(rotateY) +","+
str(type) +","+
str(red(colBox)) +","+
str(green(colBox)) +","+
str(blue(colBox)) ;
}
//
} // class
//
``````
• there is still a lot to do:

• technically the variables translatex,translatey,translatez, sizeBox etc. before setup() are not necessary but should be just Box3D placingBox; or so.

• rotation of one block is not supported

• no color selector

• no textures for boxes

• no save and load scenes

• no PLAY mode where you can just look at the scene (run through it) without editing it

Chrisir ;-)

• Thank you! This has solved my problem. Also, here is the code, modified to suit my needs:

``````import peasy.PeasyCam;

PeasyCam cam;

final float gravity = 1; //Inaccurate gravity simulation (impulse rather than force)

// ArrayLists for the class
ArrayList<Box3D> boxes = new ArrayList();

// this is a very important size: size boxes
float sizeBox = 70.0;
float sizeLimit = 180;

float rotationX;
float rotationY;
float rotationZ;

float translatex=-sizeBox;
float translatey=-sizeBox;
float translatez=0;

float z = 1.0;

int objectNumber = 0;

// folded triangle
PShape s;

float offsetZ=400;

color colCurrent=color(0, 0, 255);

boolean showHelpText=true;

void setup() {

size(500, 500, P3D);
background(0);
sphereDetail(32);

cam = new PeasyCam(this, 400); // new

s = createShape();
s.beginShape();
s.fill(255, 0, 0);
s.stroke(177);
s.vertex(100, 0, -100);
s.vertex(-60, 0, 200);
s.vertex(-50, 60, -30);
s.vertex(110, 160, 40);
s.scale(0.4);
s.endShape(CLOSE);
}

void draw() {
background(0);
lights();

for (Box3D b : boxes ) {
b.display();
}

showObject();

cam.beginHUD();
if (showHelpText) {
fill(255); // white
text ("Use PeasyCam. Use wasd and pl; r/g/b for colors, space bar to toggle object, RETURN to enter object to list.\n\n"
+"Use x to switch this text on and off. \n"
+"Use Mousewheel to zoom, double click to reset view. The box you move has a white outline. An item that has been added to the list is marked with a gray box.\n"
+"On adding to the list the placing box moves two units left. \n"
+"Current: "
+translatex
+", "
+translatey
+", "
+translatez,
19, 19);
}

if (keyPressed)
keyPressed_ForContinuusKeyinput();

cam.endHUD();
}

// -----------------------------------------------------------

void showObject() {

// show object

pushMatrix();

translatey+=gravity;

translatex=constrain(translatex,-sizeLimit,sizeLimit);
translatey=constrain(translatey,-sizeLimit,sizeLimit);
translatez=constrain(translatez,-sizeLimit,sizeLimit);

fill(colCurrent); // color
//translate(width/3, height/2, 0);
translate(translatex, translatey, translatez);
//rotateZ(rotationZ);
//rotateY(rotationY);
//rotateX(rotationX);

stroke(255);

if (objectNumber==0) {
//stroke(111);
box(sizeBox);
} else if (objectNumber==1) {
s.setFill(colCurrent);
shape(s, 0, 0);
} else if (objectNumber==2) {
//noStroke();
sphere(sizeBox);
}//else

popMatrix();
}

// -----------------------------------------------------------

void keyPressed_ForContinuusKeyinput() {
// keyPressed for registering a key throughout

float speed = 3.9;

switch(key) {

case 'a':
translatex-=speed;
break;

case 'd':
translatex+=speed;
break;

case 'w':
case ' ':
translatey-=speed; //Conflicting keypress info: change object
break;

case SHIFT:
case 's':
translatey+=speed;
break;

// --

case 'p':
translatez-=speed;
break;

case 'l':
translatez+=speed;
break; //Unnecessary in 2D version, but useful

// -----

//
}//switch
//
}//func

// ----------------------------

void keyPressed() {

// keyPressed for registering a single key only

switch(key) {
/*
case ' ':
objectNumber++;
if (objectNumber>2)
objectNumber=0;
key=0;
break;
*/ //Object switch disabled in favor of jumping

case RETURN:
case ENTER:
Box3D newBox = new Box3D (
translatex,
translatey,
translatez,
rotationY,
objectNumber,
colCurrent
);
translatex-=sizeBox*2;
break;

// ---
//colors

case 'r':
colCurrent=color(255, 0, 0);
break;

case 'b':
colCurrent=color(0, 0, 255);
break;

case 'g':
colCurrent=color(0, 255, 0);
break;

// --

case 'x':
showHelpText = !showHelpText;
break;
}//switch
//
} //func

//=============================================================

class Box3D {

float x=mouseX, y=410, z=mouseY;

float offsetX=0;
float offsetZ2=0;

float rotateY=0;
color colBox = color(255, 0, 0);

// type
final int boxTypeUndefined = -1;
final int boxType0   = 0;
final int boxType1   = 1;
final int boxType2   = 2;
// more needed !!!!! ????
int type = boxTypeUndefined;

// constr - full
Box3D(float x_,
float y_,
float z_,
float rotateY_,
int type_,
color col1_) {
//

x=x_;
y=y_;
z=z_;

rotateY= rotateY_;
type=type_;

colBox=col1_;
} // constr 2

void display() {
pushMatrix();

translate(x, y, z);

fill(colBox);
noStroke();

// depending on the current buttons tag
//
switch (type) {

case boxTypeUndefined:
// undefined
break;

case boxType0:
stroke(111);
box(sizeBox);
break;

case boxType1:
s.setFill(colBox);
shape(s, 0, 0);
break;

case boxType2:
noStroke();
sphere(sizeBox);
break;

default:
// error
break;
}//switch

if (showHelpText) {
translate(sizeBox/2, -sizeBox/2, sizeBox/2);

fill(111);
stroke(0);
box(sizeBox/6);
}

popMatrix();
} // method

String toString() {
return
str(x) +","+
str(y) +","+
str(z) +","+
str(rotateY) +","+
str(type) +","+
str(red(colBox)) +","+
str(green(colBox)) +","+
str(blue(colBox)) ;
}
//
} // class
//
``````
• ;-)

• This thread has been closed, in favor of QueasyCam. You can now stop commenting.

P.S. I looked at the source code, and it uses camera(). I copied down the source code, and embedded it in my own script. Here it is, for a TerraTech clone instead of a Minecraft clone:

``````// Variables
String KEY_MOVE_FORWARD_1 = 'w';
String KEY_MOVE_FORWARD_2 = 'W';
String KEY_MOVE_LEFT_1 = 'a';
String KEY_MOVE_LEFT_2 = 'A';
String KEY_MOVE_BACK_1 = 's';
String KEY_MOVE_BACK_2 = 'S';
String KEY_MOVE_RIGHT_1 = 'd';
String KEY_MOVE_RIGHT_2 = 'D';
String KEY_MOVE_UP_1 = 'q';
String KEY_MOVE_UP_2 = 'Q';
String KEY_MOVE_DOWN_1 = 'e';
String KEY_MOVE_DOWN_1 = 'E';
String KEY_JUMP = ' ';

boolean debugMode = true;
float friction = 0.8;
int debugSetting = 0;

PVector mouse = new PVector();
PVector prevMouse = new PVector();
Robot robot = new Robot();

PVector forward = new PVector();
PVector right = new PVector();
PVector up = new PVector(0, 1, 0);
PVector position = new PVector();
PVector velocity = new PVector();
PVector center = new PVector();

void newGame() {

// Generate noise map
// Introduction sequence
// Tutorial sequence, if enabled in new game menu
}

void setup() {

// Title screen
// Menu (buttons, checkboxes, random seed, etc.)
}

void draw() {

// Mouse looping
if (mouse.x < 1 && (mouse.x - prevMouse.x) < 0) {
robot.mouseMove(width - 2, mouse.y);
mouse.x = width - 2;
prevMouse.x = width - 2;
}
if (mouse.x > width - 2 && (mouse.x - prevMouse.x) > 0) {
robot.mouseMove(2, mouse.y);
mouse.x = 2;
prevMouse.x = 2;
}
if (mouse.y < 1 && (mouse.y - prevMouse.y) < 0) {
robot.mouseMove(mouse.x, height - 2);
mouse.y = height - 2;
prevMouse.y = height - 2;
}
if (mouse.y > height - 1 && (mouse.y - prevMouse.y) > 0) {
robot.mouseMove(mouse.x, 2);
mouse.y = height - 2;
prevMouse.y = 2;
}

// Pan and tilt commands
pan += map(mouse.x - prevMouse.x, 0, width, 0, TAU) * sensitivity;
tilt += map(mouse.y - prevMouse.y, 0, height, 0, PI) * sensitivity;
tilt = constrain(tilt, -PI/2.01, PI/2.01);
if (tilt == PI/2) tilt += 0.001;

// Forward and right commands
forward.x = cos(pan);
forward.y = tan(tilt);
forward.z = sin(pan);
forward.normalize();

right.x = sin(pan);
right.y = 0;
right.z = -cos(pan);

// Controls
prevMouse.x = mouse.x;
prevMouse.y = mouse.y;

if (keyPressed) {
switch(key) {

case KEY_MOVE_FORWARD_1:
case KEY_MOVE_FORWARD_2:
break;

case KEY_MOVE_LEFT_1:
case KEY_MOVE_RIGHT_1:
break;

case KEY_MOVE_BACK_1:
case KEY_MOVE_BACK_2:
velocity.sub(PVector.mult(forward, speed));
break;

case KEY_MOVE_RIGHT_1:
case KEY_MOVE_RIGHT_2:
velocity.sub(PVector.mult(right, speed));
break;

case KEY_JUMP:
break;
}

if (debugMode) {
switch(key) {

case KEY_MOVE_UP_1:
case KEY_MOVE_UP_2:
break;

case KEY_MOVE_DOWN_1:
case KEY_MOVE_DOWN_2:
velocity.sub(PVector.mult(up, speed));
break;
}
}
}

// Movement and camera

velocity.mult(friction);
camera(position.x, position.y, position.z,
center.x,   center.y,   center.z,
up.x,       up.y,       up.z);

// Actual graphics
if (debugMode) {
switch(debugSetting) {

case 0:

// Wavy cubes

break;

case 1:

// Grid
break;
}
// Draw cube
} else {
// Draw tech(s)
// Draw terrain, generated in noise map
}
}
``````
• Also, I forgot to include these lines at the very beginning, for the robot:

``````import java.awt.*;
import java.awt.event.*;
``````
• Thank you!

• You're welcome!