I'm currently making a project similar to John Conway's Game of Life, and I would like to know how to rotate a point without using rotate().
When I use it it rotates it around the canvas, its difficult to explain here's the code:
//Setup
var x;
var y;
var x2;
var y2;
var x3;
var y3;
let slider;
function setup() {
//Setup and Varibles
createCanvas(400, 400);
x = 200;
y = 200;
x2 = 150;
y2 = 100;
x3 = 300;
y3 = 220;
slider = createSlider(0, 255, 100);
slider.position(10, 10);
slider.style("width", "80px");
}
function draw() {
let val = slider.value();
background(54);
stroke(255);
strokeWeight(1);
line(x, y, x + 30, y - 10);
strokeWeight(10);
point(x, y);
var r = ceil(random(5));
//Player 1 AI
switch (r) {
case 0:
x = x + 2;
break;
case 1:
x = x - 2;
break;
case 2:
y = y + 2;
break;
case 3:
y = y - 2;
break;
case 4:
//EXTRA
break;
}
point(x2, y2);
var ra = floor(random(5));
//Player 2 AI
switch (ra) {
case 0:
x2 = x2 + 2;
break;
case 1:
x2 = x2 - 2;
break;
case 2:
y2 = y2 + 2;
break;
case 3:
y2 = y2 - 2;
break;
case 4:
//EXTRA
break;
}
//Player 3 AI
var ran = ceil(random(5));
point(x3, y3);
switch (ran) {
case 0:
x3 = x3 + 2;
break;
case 1:
x3 = x3 - 2;
break;
case 2:
y3 = y3 + 2;
break;
case 3:
y3 = y3 - 2;
break;
case 4:
//EXTRA
break;
}
//Collision detection between Players
var d = int(dist(x2, y2, x, y));
var d2 = int(dist(x3, y3, x, y));
var d3 = int(dist(x2, y2, x3, y3));
function reset() {
x = 200;
y = 200;
x2 = 150;
y2 = 100;
x3 = 300;
y3 = 220;
}
noStroke();
text("1", x - 3, y - 5);
text("2", x2 - 3, y2 - 5);
text("3", x3 - 3, y3 - 5);
if (d === 10) {
reset();
}
if (d2 === 10) {
reset();
}
if (d3 === 10) {
reset();
}
//Barriers
if (y === 0) {
reset();
}
if (y2 === 0) {
reset();
}
if (y3 === 0) {
reset();
}
if (y === 400) {
reset();
}
if (y2 === 400) {
reset();
}
if (y3 === 400) {
reset();
}
if (x === 400) {
reset();
}
if (x2 === 400) {
reset();
}
if (x3 === 400) {
reset();
}
if (x === 0) {
reset();
}
if (x2 === 0) {
reset();
}
if (x3 === 0) {
reset();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
Thank You
https://editor.p5js.org/
I'm new p5js so sorry if the answer is simple!
Unless the shape in question is trivially simple (i.e. just a line). Then I think you will definitely want to utilize the rotate() function. It sounds like you've been trying to use just rotate(), which will rotate all future drawing commands around the origin (position 0, 0) of the canvas. In order to rotate a particular object around its own origin you need to translate that origin, then perform the rotation, then draw the object. After drawing a rotated object you can use pop() to reset the translation and rotation back to the original. Here's an example:
function setup() {
createCanvas(windowWidth, windowHeight);
// Draw squares centered on the origin
rectMode(CENTER);
}
function draw() {
background(100);
for (let i = 1; i <= 4; i++) {
// Save the current state (translation/rotation/etc)
push();
// Translate to the origin of the shape
translate(mouseX * i / 4, mouseY * i / 4);
// Rotate around the origin
rotate(millis() / 1000 * PI / 2);
// Because we've translated to the origin, we draw the square at 0, 0
square(0, 0, 50);
// Restore the state saved with push();
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
In order to demonstrate why this is easier than the alternative, here is an example that does the same thing but does not use translate() or rotate():
function setup() {
createCanvas(windowWidth, windowHeight);
}
// Declare each vertex of our geometry as a vector from the origin.
const rectPoints = [
new p5.Vector(-25, -25),
new p5.Vector(25, -25),
new p5.Vector(25, 25),
new p5.Vector(-25, 25)
];
function draw() {
background(100);
let angle = millis() / 1000 * PI / 2;
// Use p5.Vector.rotate to rotate each of the points that defines our geometry
let rotatedRectPoints = rectPoints.map(v => v.copy().rotate(angle));
for (let i = 1; i <= 4; i++) {
// We can't using normal primitives like square(), so we have to draw shapes
// with beginShape/endShape
beginShape();
for (const p of rotatedRectPoints) {
vertex(p.x + mouseX * i / 4, p.y + mouseY * i / 4);
}
endShape();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
Related
I have an image which I am trying to show using a spiral with varying thickness depending upon the image pixel. But the thickness of my line/ellipses in spiral is not coming out correctly.
The image I am using:
The image I am getting
As you can see for whatever reason the bottom right quadrant is getting thick and nothing else, this is happening even if I use other images.
My code:
FG = '#222323';
BG = '#f0f6f0';
function preload() {
Img = loadImage('black.png');
}
function setup() {
createCanvas(500, 500);
Img.resize(500, 500);
background(BG);
fill(FG);
colorMode(HSB, 255);
noLoop();
noStroke();
}
function draw() {
var r = width;
var a = 0;
while (r > 1) {
strokeWeight(1);
var x1 = r * cos(a);
var y1 = r * sin(a);
a += 0.01;
r -= 0.03;
var x2 = r * cos(a);
var y2 = r * sin(a);
let c = Img.get(x1, y1);
let b = brightness(c);
const val = map(b, 0, 255, 1, 10);
push();
translate(width/2, height/2);
ellipse(x1, y1, val, val);
pop();
}
}
The coordinates where you're sampling from aren't the same where you're rendering.
Because you use translate(), the ellipses themselves are offset based on the centre (but there's nothing changing where you're sampling from in the image (x1,y1).
You can offset x1,y1 to take the centre of the stage into account and then you sample from the right location (and draw offset to the centre):
FG = '#222323';
BG = '#f0f6f0';
function preload() {
// Img = loadImage('black.png');
Img = loadImage('data:image/png;base64,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');
}
function setup() {
createCanvas(500, 500);
Img.resize(500, 500);
background(BG);
fill(FG);
colorMode(HSB, 255);
noLoop();
noStroke();
}
function draw() {
var r = width;
var a = 0;
const centerX = width * 0.5;
const centerY = height * 0.5;
while (r > 1) {
var x1 = centerX + (r * cos(a));
var y1 = centerX + (r * sin(a));
a += 0.01;
r -= 0.03;
let c = Img.get(x1, y1);
let b = brightness(c);
const val = map(b, 0, 255, 1, 10);
ellipse(x1, y1, val, val);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
(Notice the central area where the source image has a black circle is what based on your mapping. You can reverse that as well if that's more interesting (const val = map(b, 0, 255, 10, 1);))
Im playing around with the prime spiral code from Dan Shiffman:
https://www.youtube.com/watch?v=a35KWEjRvc0&t=716s&ab_channel=TheCodingTrain
I need to use this code as a background to another sketch, but due to the moving nature of the spiral its impossible that the spiral will not draw ontop of the other sketch, even with p5.layers.
I am therefore searching for a way to refactor this code into something that draw all the figures at once so use it as a background.
My idea is to create some kind of for loop in setup, but i am afraid its to big of nut to crack for me.
let x, y;
let step = 1;
let stepSize = 20;
let numSteps = 1;
let state = 0;
let turnCounter = 1;
let totalSteps;
let offset = 0;
function isPrime(value) {
if (value == 1) return false;
for (let i = 2; i <= sqrt(value); i++) {
if (value % i == 0) {
return false;
}
}
return true;
}
function setup() {
createCanvas(500, 500);
const cols = width / stepSize;
const rows = height / stepSize;
totalSteps = cols * rows;
x = width / 2;
y = height / 2;
background(0);
}
function draw() {
primeSpiral(20, 1)
primeSpiral(30, 200)
incrementStep();
noStroke();
}
function incrementStep()
{
switch (state) {
case 0:
x += stepSize;
break;
case 1:
y -= stepSize;
break;
case 2:
x -= stepSize;
break;
case 3:
y += stepSize;
break;
}
if (step % numSteps == 0) {
state = (state + 1) % 4;
turnCounter++;
if (turnCounter % 2 == 0) {
numSteps++;
}
}
step++;
if (step > totalSteps) {
noLoop();
}
}
function primeSpiral(offset, color){
if (!isPrime(step+offset)) {
//might put something here
} else {
let r = stepSize * 0.5;
fill(color, 99, 164);
push();
translate(x, y);
rotate(-PI / 4);
triangle(-r, +r, 0, -r, +r, +r);
pop();
}
}
You can move the code from draw() to the loop in setup(), here is example:
...
function setup() {
createCanvas(500, 500);
const cols = width / stepSize;
const rows = height / stepSize;
totalSteps = cols * rows;
x = width / 2;
y = height / 2;
background(0);
for (let i = 0; i<100; i++) { // 100 is the number of processed frames, you can change it as you need
primeSpiral(20, 1)
primeSpiral(30, 200)
incrementStep();
noStroke();
}
}
function draw() { // now draw is empty and you can place new code here
}
...
I understand that there are a number of answered questions on here asking the exact same thing. However, I have tried to implement the solution (cosine correction) and have had little success. Note: it is not implemented in this version of the code.
In terms of my code, I'll upload the whole thing but the part that likely needs fixing is the Player class. The rest is fairly boring stuff. I also know that it runs based off of images that you won't have, but for testing feel free to use any 600x600 image that is only black and white. Or contact me for mine. White denotes walls. I'll also upload a screenshot of the warped walls. Controls are WASD for movement, plus some glitchy mouse controls to change the view (will be fixed) as well as hold m to see a map of the current level.
Screenshot of it running
PImage maze;
int stepSize, renderDistance;
float viewStep, fov, moveSpeed;
float minLine, maxLine;
Player p;
boolean w, s, a, d, map;
void setup() {
size(600, 600);
background(0);
strokeWeight(3);
maze = loadImage("testmaze3.png");
stepSize = 1;
fov = PI/4;
viewStep = fov/(width/4);
renderDistance = 300;
moveSpeed = 2;
minLine = 0;
maxLine = 200;
colorMode(RGB, renderDistance);
p = new Player(width/2, height/2, 0);
w = false;
s = false;
a = false;
d = false;
}
void draw() {
maze.loadPixels();
if (map) {
pushStyle();
background(maze);
fill(255, 0, 0);
noStroke();
ellipse(p.x, p.y, 10,10);
stroke(renderDistance);
pushMatrix();
translate(p.x, p.y);
line(0, 0, renderDistance*cos(p.direction), renderDistance*sin(p.direction));
popMatrix();
popStyle();
}
pushMatrix();
translate(p.x, p.y);
if (w) {
if (maze.get(int(p.x + moveSpeed*cos(p.direction)), int(p.y + moveSpeed*sin(p.direction))) != color(renderDistance)) {
p.x += moveSpeed*cos(p.direction);
p.y += moveSpeed*sin(p.direction);
}
}
if (s) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction)), int(p.y - moveSpeed*sin(p.direction))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction);
p.y -= moveSpeed*sin(p.direction);
}
}
if (d) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction-PI/2)), int(p.y - moveSpeed*sin(p.direction-PI/2))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction-PI/2);
p.y -= moveSpeed*sin(p.direction-PI/2);
}
}
if (a) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction+PI/2)), int(p.y - moveSpeed*sin(p.direction+PI/2))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction+PI/2);
p.y -= moveSpeed*sin(p.direction+PI/2);
}
}
popMatrix();
p.direction += ((float)mouseX-(float)pmouseX)/100;
if (!map) {
pushStyle();
noStroke();
fill(0, 0, renderDistance);
rect(0, 0, width, height/2);
fill(0, 0, renderDistance*0.6);
rect(0, height/2, width, height);
popStyle();
p.display();
}
}
void keyPressed() {
if (key == 'w') {
w = true;
}
if (key == 's') {
s = true;
}
if (key == 'a') {
a = true;
}
if (key == 'd') {
d = true;
}
if (key == 'm') {
map = true;
}
}
void keyReleased() {
if (key == 'w') {
w = false;
}
if (key == 's') {
s = false;
}
if (key == 'a') {
a = false;
}
if (key == 'd') {
d = false;
}
if (key == 'm') {
map = false;
}
}
class Player {
float x, y, direction;
Player(int x, int y, float direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
void display() {
maze.loadPixels();
for (float i = direction - fov; i < direction + fov; i += viewStep) {
FloatList line = new FloatList();
line = rayCast(i);
float length_ = (height - maxLine - minLine - map(line.get(2), 0, renderDistance, minLine, maxLine));
stroke(renderDistance - line.get(2), 0, 0);
if (line.get(3) == 1){
stroke(renderDistance - line.get(2));
}
if (renderDistance - line.get(2) > 1) {
line(map(i, direction - fov/2, direction + fov, 0, width), height/2 + length_/2, map(i, direction - fov/2, direction + fov, 0, width), height/2 - length_/2);
}
}
}
FloatList rayCast(float direction) {
FloatList out = new FloatList();
float rayx = x;
float rayy = y;
int steps = 0;
for (int i = 0; i < renderDistance; i++) {
if (maze.get(int(rayx), int(rayy)) != color(0)) {
break;
}
rayx += stepSize * cos(direction);
rayy += stepSize * sin(direction);
steps++;
}
out.append(rayx);
out.append(rayy);
out.append(steps);
if (rayx < 0 || rayx > width || rayy > height || rayy < 0) {
out.append(1);
} else {
out.append(0);
}
return out;
}
}
Your raycasting algorithm calculates the distance from the wall to an infinitely small focus point in the camera. When we try to project this onto our screen we get a distorted image because our screen is a plane and not a point or sphere.
To fix the distortion we have to calculate the distance from the wall to our screen instead of the focus point. This can be done with simple trigonometry:
multiply the raw (euclidean) distance by cos(angle) and you get the distance to the screen.
drawing
So after cleaning up the code and adding the correction it looks like this:
void display() {
maze.loadPixels();
float wallHalfHeight = 50;
float distanceFocusProjection = (height / 2) / tan(fov);
for (float angle = -fov; angle < fov; angle += viewStep) {
float euclideanDist = rayCast(direction + angle);
if (euclideanDist < renderDistance) {
float distToScreen = euclideanDist * cos(angle);
float scanLineHalfHeight = wallHalfHeight * (distanceFocusProjection / distToScreen);
float scanLineX = map(angle, -fov, fov, 0, width);
stroke(renderDistance - distToScreen, 0, 0);
line(scanLineX, height/2 + scanLineHalfHeight, scanLineX, height/2 - scanLineHalfHeight);
}
}
}
float rayCast(float angle) {
PVector position = new PVector(x, y);
PVector direction = PVector.fromAngle(angle); //new PVector(cos(angle), sin(angle));
int distance;
for(distance = 0; distance < renderDistance; distance++) {
if (maze.get(round(position.x), round(position.y)) != color(0)) {
break;
}
position.add(direction);
}
return distance;
}
I've made a square grid on top of the canvas and also a cruve (that is meant to have a fading trail). I made them seperately and tried combining them so the curve would appear on top of the grid. However, it doesn't show the curve.
I've commented out the grid so it's easier to see the curve.
How do I get this to work?
var cols = 10;
var rows = 10;
var t = 0;
var particleArray = [];
function setup() {
createCanvas(600, 600);
background(0);
fill(100);
rect(0, 0, 550, 550, 25);
}
// blue grid
function draw() {
/*for (var c = 0; c < cols; c++) {
for (var r = 0; r < rows; r++) {
var XO = 25 + c * 50;
var YO = 25 + r * 50;
stroke(0);
fill(100,149,237);
rect(XO, YO, 50, 50);
noLoop();
// :(
}
}
*/
//curve
y = width / 2 + 270 * sin(3 * t + PI / 2) - 25;
x = height / 2 + 270 * sin(1 * t) - 25;
particleArray.push(new Particle(x, y, t));
for (i=0; i<particleArray.length; i++) {
particleArray[i].show(t);
}
if (particleArray.length > 700) {
particleArray.shift();
}
t += .01;
}
function Particle(x, y, t) {
this.x = x;
this.y = y;
this.t = t;
this.show = function(currentT) {
var _ratio = t / currentT;
_alpha = map(_ratio, 0, 1, 0, 255); //points will fade out as time elaps
fill(255, 255, 255, _alpha);
ellipse(x, y, 5, 5);
}
}
I don't know if this was intentional but you called noLoop() function where you're drawing the grid. If you comment that out it works.
My problem is as in the title. I am trying to write a simple game in processing with a car that you can drive on a 2D plane. I wanted to create a rotation of the car since it seems crucial so I did it as described here:Rotating points in 2D
But my implementation seems to fail a bit. You see, when I hit left of right arrow the car actually rotates but shrinks in size as it is rotating and after few turns it completely dissapears. Can you show me what am I missing here? Thanks in advance! Code of my functions:
class Point
{
float x, y;
Point(float xx, float yy)
{
x = xx;
y = yy;
}
Point()
{
x = y = 0.0;
}
void Rotate(Point center, float angle)
{
float s = sin(angle);
float c = cos(angle);
y = center.y + ((y-center.y) * c + (x-center.x) * s);
x = center.x + ((x-center.x) * c - (y-center.y) * s);
}
}
class Car
{
Point LT;
Point RT;
Point LB;
Point RB;
Point center;
float r;
float acceleration;
Car()
{
LT = new Point(10, 10);
RT = new Point (30, 10);
LB = new Point(10, 50);
RB = new Point(30, 50);
r = sqrt(pow(15-30, 2) + pow(25-10, 2));
}
Car(Point lt, Point rt, Point lb, Point rb)
{
LT = lt;
RT = rt;
LB = lb;
RB = rb;
center = new Point(abs((LT.x - RT.x)/2), abs((LT.y - LB.y)/2));
r = sqrt(pow(center.x -LT.x, 2) + pow(center.y - LT.y, 2));
}
Car(Point Center, float w, float h)
{
center = Center;
LT = new Point(center.x - w/2, center.y - h/2);
RT = new Point (center.x + w/2, center.y - h/2);
LB = new Point(center.x - w/2, center.y + h/2);
RB = new Point(center.x + w/2, center.y + h/2);
r = sqrt(pow(center.x -LT.x, 2) + pow(center.y - LT.y, 2));
}
void Show()
{
fill(45, 128, 156);
beginShape();
vertex(LT.x, LT.y);
vertex(RT.x, RT.y);
vertex(RB.x, RB.y);
vertex(LB.x, LB.y);
endShape();
}
void Update()
{
}
void Turn(float angle)
{
LT.Rotate(center, angle);
RT.Rotate(center, angle);
RB.Rotate(center, angle);
LB.Rotate(center, angle);
}
void Accelerate(float accel)
{
}
}
In main I only use car.Show() and I turn by -0.1 per left cliock and 0.1 per right click
EDIT
If you want to see whole code visit my github repo
Unfortunately I can't explain more at the moment, but here's a simpler option using one of the formulas you've pointed to:
Car car = new Car();
void setup(){
size(300,300);
// this helps draw rectangles from centre (as opposed to corner (default))
rectMode(CENTER);
car.position.set(150,150);
}
void draw(){
background(255);
if(keyPressed){
if(keyCode == UP){
car.speed = 1;
}
}
car.draw();
}
void keyPressed(){
if(keyCode == LEFT){
car.steer -= radians(10);
}
if(keyCode == RIGHT){
car.steer += radians(10);
}
}
void keyReleased(){
if(keyCode == UP){
car.speed = 0;
}
}
class Car{
PVector position = new PVector();
PVector velocity = new PVector();
float speed;
float steer;
void update(){
// use the same polar to cartesian coordinates formulate for quick'n'dirty steering
velocity.set(cos(steer) * speed,sin(steer) * speed);
// update position based on velocity
position.add(velocity);
}
void draw(){
update();
// use a nested coordinate system to handle translation and rotation for us
// order of operations is important
pushMatrix();
translate(position.x,position.y);
rotate(steer);
rect(0,0,30,15);
popMatrix();
}
}
Update
The main issue with points shrinking is you're cumulatively transforming the points when you rotate them. After each transformation there is no history of what the x,y were. Instead you should return a new point that is transformed, thus "remembering" the old x,y position.
Bellow is a tweaked version of your code, minus the two constructor variants.
Hopefully the comments will help:
Car car = new Car();
void setup(){
size(300,300);
}
void draw(){
if(keyCode == UP){
if(keyPressed){
car.Accelerate(1);
}else{
car.Accelerate(0);
}
}
car.Update();
background(255);
car.Show();
}
void keyPressed(){
if(keyCode == LEFT){
car.Turn(radians(-3));
}
if(keyCode == RIGHT){
car.Turn(radians(+3));
}
}
class Point
{
float x, y;
Point(float xx, float yy)
{
x = xx;
y = yy;
}
Point()
{
x = y = 0.0;
}
Point Rotate(Point center, float angle)
{
float s = sin(angle);
float c = cos(angle);
// return a new point (a rotated copy), rather than overwriting this one
return new Point(center.x + ((x-center.x) * c - (y-center.y) * s),
center.y + ((y-center.y) * c + (x-center.x) * s));
}
// translate by another point
void AddToSelf(Point point){
this.x += point.x;
this.y += point.y;
}
// pretty print info when using println()
String toString(){
return "[Point x=" + x + " y="+ y +"]";
}
}
class Car
{
Point LT;
Point RT;
Point LB;
Point RB;
Point center;
float r;
float acceleration;
// car angle: used to compute velocity and update vertices
float angle;
// car position: used to offset rendering position of the corners
Point position;
// car velocity: amount by which position translates
Point velocity = new Point();
Car()
{
float x = 10;
float y = 10;
float w = 40;
float h = 20;
// setup corners with no translation
LT = new Point(0 , 0 );
RT = new Point(0 + w, 0 );
LB = new Point(0 , 0 + h);
RB = new Point(0 + w, 0 + h);
// setup initial position
position = new Point(x,y);
center = new Point(w / 2, h / 2);
r = sqrt(pow(15-30, 2) + pow(25-10, 2));
}
//Car(Point lt, Point rt, Point lb, Point rb)
//{
// LT = lt;
// RT = rt;
// LB = lb;
// RB = rb;
// center = new Point(abs((LT.x - RT.x)/2), abs((LT.y - LB.y)/2));
// r = sqrt(pow(center.x -LT.x, 2) + pow(center.y - LT.y, 2));
//}
//Car(Point Center, float w, float h)
//{
// center = Center;
// LT = new Point(center.x - w/2, center.y - h/2);
// RT = new Point (center.x + w/2, center.y - h/2);
// LB = new Point(center.x - w/2, center.y + h/2);
// RB = new Point(center.x + w/2, center.y + h/2);
// r = sqrt(pow(center.x -LT.x, 2) + pow(center.y - LT.y, 2));
//}
void Show()
{
fill(45, 128, 156);
beginShape();
// render corners offset by the car position
vertex(position.x + LT.x, position.y + LT.y);
vertex(position.x + RT.x, position.y + RT.y);
vertex(position.x + RB.x, position.y + RB.y);
vertex(position.x + LB.x, position.y + LB.y);
endShape(CLOSE);
}
void Update()
{
// update velocity based on car angle and acceleration
velocity.x = cos(angle) * acceleration;
velocity.y = sin(angle) * acceleration;
// update position based on velocity
position.AddToSelf(velocity);
}
void Turn(float angle)
{
this.angle += angle;
// replace the old point with the transformed points
// (rather than continuosly transforming the same point)
LT = LT.Rotate(center, angle);
RT = RT.Rotate(center, angle);
RB = RB.Rotate(center, angle);
LB = LB.Rotate(center, angle);
}
void Accelerate(float accel)
{
acceleration = accel;
}
}