sandy99 38
Postad: 6 apr 2020

Arduino och Processing: Spel

Hej, vi håller på att göra ett spel med en Arduino Uno, knapp och accelerometer (ADXL345 accelerometer).

I spelet vill vi att en boll ska studsa mot en paddel på nedre delen av skärmen och träffa brickor på övre delen, som går sönder när bollen träffar dem, se bild.

Vi har följt den här beskrivningen men ändrat så att det är den typ accelerometer vi använder.

vårt problem är att paddeln i spelet inte syns i spelet, den syns innan spelet börjar precis som på skärmen ovan men sen när man spelar syns den inte.

Arduinokod:

const int BUFFER_SIZE=16;
int buffer[NUM_AXES][BUFFER_SIZE];
int buffer_pos[NUM_AXES]={0};
Bounce button(Button_Pin, 20);

void setup(){
Wire.begin();
Wire.beginTransmission(ADXL345);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
Serial.begin(19200);
pinMode(Button_Pin, INPUT);
}

int get_axis(const int axis){
delay(1);
buffer[axis][buffer_pos[axis]]=Wire.read()<<8|Wire.read();
buffer_pos[axis]=(buffer_pos[axis]+1)%BUFFER_SIZE;
long sum=0;
for(int i=0; i<BUFFER_SIZE; i++)
sum+= buffer[axis][i];
return round(sum/BUFFER_SIZE);
}

int get_x(){return get_axis(0);}
int get_y(){return get_axis(1);}
int get_z(){return get_axis(2);}

void loop(){
Wire.beginTransmission(ADXL345);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(ADXL345,6,true);
Serial.print(get_x());
Serial.print(" ");
Serial.print(get_y());
Serial.print(" ");
Serial.print(get_z());
Serial.print(" ");
if(button.update())
Serial.println(button.read()==HIGH ? "1" : "0");
else
Serial.println("0");

delay(50);
}

 

PROCESSING KOD:

import processing.serial.*;

Serial arduinoPort;

final int COLUMNS=7;
final int ROWS=4;
final int BALL_RADIUS=8;
final int BALL_DIAMETER=BALL_RADIUS*2;
final int MAX_VELOCITY=8;
final int MARGIN=10;
final int PADDLE_WIDTH=60;
final int PADDLE_HEIGHT=15;
final int BRICK_WIDTH=40;
final int BRICK_HEIGHT=20;
final int HEIGHT=300;
final int LINE_FEED=10;

int px, py;
int vx, vy;
int xpos=150;
int[][] bricks= new int[COLUMNS][ROWS];

boolean buttonPressed=false;
boolean paused=true;
boolean done=true;

void setup(){
size(300, 300);
noCursor();
textFont(loadFont("Verdana-Bold-36.vlw"));
initGame();
println(Serial.list());
arduinoPort=new Serial(this, "COM3", 19200);
arduinoPort.bufferUntil(10);
}

void initGame(){
initBricks();
initBall();

}

void initBricks(){
for(int x=0; x<COLUMNS; x++)
for(int y=0; y<ROWS; y++)
bricks[x][y]=1;
}

void initBall(){
px=width/2;
py=height/2;
vx=int(random(-MAX_VELOCITY, MAX_VELOCITY));
vy=-2;
}


void draw(){
background(0);
stroke(255);
strokeWeight(3);

done=drawBricks();
if(done){
paused=true;
printWinMessage();
}
if(paused)
printPauseMessage();
else
updateGame();

drawBall();
drawPaddle();
}

boolean drawBricks(){
boolean allEmpty=true;
for(int x=0; x<COLUMNS; x++){
for(int y=0; y<ROWS; y++){
if(bricks[x][y]>0){
allEmpty=false;
fill(0, 0, 100+y*8);
rect(
MARGIN+x*BRICK_WIDTH,
MARGIN+y*BRICK_HEIGHT,
BRICK_WIDTH,
BRICK_HEIGHT
);
}
}
}
return allEmpty;
}

void drawBall(){
strokeWeight(1);
fill(128, 0, 0);
ellipse(px, py, BALL_DIAMETER, BALL_DIAMETER);
}

void drawPaddle(){
int x=xpos - PADDLE_WIDTH/2;
int y=height - 25;
strokeWeight(1);
fill(128);
rect(x, y, 60, 15);
}

void printWinMessage(){
fill(225);
textSize(36);
textAlign(CENTER);
text("YOU WIN", width/2, height*2/3);
}

void printPauseMessage(){
fill(128);
textSize(16);
textAlign(CENTER);
text("Press button to continue", width/2, height*5/6);
}

void updateGame(){
if(ballDropped()){
initBall();
paused=true;
} else{
checkBrickCollision();
checkWallCollision();
checkPaddleCollision();
px+=vx;
py+=vy;
}
}

boolean ballDropped(){
return py+vy> height - BALL_RADIUS;
}

boolean inXRange(final int row, final int v){
return px + v > row*BRICK_WIDTH&&
px+v < (row+1)*BRICK_WIDTH+BALL_DIAMETER;
}

boolean inYRange(final int col, final int v){
return py+v> col*BRICK_HEIGHT&&
py+v< (col+1)*BRICK_HEIGHT+BALL_DIAMETER;
}

void checkBrickCollision(){
for(int x=0; x<COLUMNS; x++){
for(int y=0; y<ROWS; y++){
if(bricks[x][y]>0){
if(inXRange(x, vx)&& inYRange(y, vy)){
bricks[x][y]=0;
if(inXRange(x, 0))
vy=-vy;
if(inYRange(y, 0))
vx=-vx;
}
}
}
}
}

void checkWallCollision(){
if(px+vx < BALL_RADIUS || px+vx > width - BALL_RADIUS)
vx=-vx;

if(py+vy < BALL_RADIUS || py+vy > height - BALL_RADIUS)
vy=-vy;
}

void checkPaddleCollision(){
final int cx=xpos;
if(py+vy >=height - (PADDLE_HEIGHT + MARGIN + 6)&&
px >= cx - PADDLE_WIDTH/2 &&
px <= cx + PADDLE_WIDTH/2)
{
vy=-vy;
vx=int(
map(
px - cx,
-(PADDLE_WIDTH/2), PADDLE_WIDTH/2,
-MAX_VELOCITY,
MAX_VELOCITY
)
);
}
}

void serialEvent(Serial port){
final String arduinoData=port.readStringUntil(LINE_FEED);
if(arduinoData!=null){
println(arduinoData);
final int[] data=int(split(trim(arduinoData), ' '));
if(data.length==4){
buttonPressed=(data[3]==1);
if(buttonPressed){
paused= !paused;
if(done){
done=false;
initGame();
}
}

if(!paused)
xpos=int(map(data[0]-2000, 252, 443, 0, 300));
}
}
}

Nu har jag aldrig använt mig av Arduino så det är möjligt att jag trampar i klaveret, men:

Kan ni alltså spela spelet så att bollen studsar mot paddeln, fast att denna är osynlig?

Jag tittade på er drawPaddle-funktion, vilken verkade vara nog så enkel att antagligen allting var rätt* i den, vilket gör att den antingen inte tillkallas på ett lämpligt vis eller att variablerna som är däri inte tilldelas värden på rätt sätt. Då det egentligen bara är en variabel som varierar varje gång som drawPaddle anropas(xpos) vars tilldelning av värde tycks ske via er Arduino-utrustning kan den utgöra en felkälla(så att programmet ritar en rektangel som befinner sig långt utanför skärmen) men är så fallet skulle spelet inte gå att spelas ens en gång. Så: Kan ni spela, fast att paddeln bara är osynlig? Om så är fallet har den potentiella felkällan eliminerats.

Det andra alternativet skulle vara funktionen inte tillkallas på ett lämpligt vis. Möjliga saker som kan orsaka problem skulle vara att funktionen aldrig tillkallas eller att andra funktionskall gör att dess effekt skrivs över. Det typiska exemplet på det senare skulle vara om bakgrunden målar över paddeln, eller att en else if-sats gör att drawPaddle aldrig anropas. Ordningen ni har i er draw-funktion gör att jag inte tror att så är fallet. else-if-satser finns närvarande men de verkar vara korrekt strukturerade.

Mitt allmänna råd är att pröva att kommentera bort kod-rader/radera kod-rader och se om effekten av raderande/bortkommenterandet blir densamma som förväntat. Om inte, har ni troligtvis hittat en felkälla.

* Jag jämför drawPaddle med drawBall, och ser att den senare har ett fill-funktionsanrop med en integer som invariabel, medan den senare har tre integers. Av skärmdumpen att döma bör detta vara ansättning av färg att fylla i med, men pröva att ha tre invariabler. Det borde inte göra någon skillnad om fill gör vad jag tror fill gör, men det vet ni antagligen mer om.

sandy99 38
Postad: 7 apr 2020

Tack, vi ska kolla på det!

När vi startar spelet så lever det sitt eget liv, utan att vi gör något så åker bollen runt och pausar av sig själv.

sandy99 38
Postad: 7 apr 2020

Jag har funderat på om det kan vara så att initGame-funktionen i processing saknar en initPaddle-funktion

Laguna Online 8626
Postad: 7 apr 2020

I sådana här lägen kan man gå från två håll:

1) Ta bort nästan allt och lägg till bara paddeln. Om den funkar då, lägg till en sak i taget tills det inte funkar.

eller

2) Ta bort lite i taget utom paddeln och se om det börjar fungera. Detta förutsätter att det har fungerat någon gång tidigare. 

Ytterligare en tanke: lägg till något i koden som ritar paddeln som visar när den koden anropas, så får du veta om den koden körs alls. Kanske lättare sagt än gjort på Arduino, men kanske blinka med en LED, eller krascha programmet.

Svara Avbryt
Close