Skip to content

Instantly share code, notes, and snippets.

@osvein
Last active December 27, 2015 17:00
Show Gist options
  • Select an option

  • Save osvein/0236f7b37fdd03de603e to your computer and use it in GitHub Desktop.

Select an option

Save osvein/0236f7b37fdd03de603e to your computer and use it in GitHub Desktop.
Pong on Arduino attempt
#include "GraphicsDisplay.h"
#define DELAY 1
#define DELAY_RESET 2
GraphicsDisplay::GraphicsDisplay(int rs, int rw, int e, volatile byte *db_port, volatile byte *db_pin, volatile byte *db_ddr, int cs0, int cs1, int rst) : Rectangle(NULL, 128, 64), rs(rs), rw(rw), e(e), db_port(db_port), db_pin(db_pin), db_ddr(db_ddr), cs0(cs0), cs1(cs1), rst(rst) {
pinMode(rs, OUTPUT);
pinMode(rw, OUTPUT);
pinMode(e, OUTPUT);
*(db_ddr) = 0xFF;
pinMode(cs0, OUTPUT);
pinMode(cs1, OUTPUT);
pinMode(rst, OUTPUT);
this->reset();
}
void GraphicsDisplay::reset() {
digitalWrite(this->rst, LOW);
delay(DELAY_RESET);
digitalWrite(this->rst, HIGH);
}
void GraphicsDisplay::enable() {
digitalWrite(this->e, LOW);
delayMicroseconds(DELAY);
digitalWrite(this->e, HIGH);
delayMicroseconds(DELAY);
}
void GraphicsDisplay::selectChip(int chip) {
digitalWrite(this->cs0, chip ? HIGH : LOW);
digitalWrite(this->cs1, chip ? LOW : HIGH);
}
void GraphicsDisplay::send(byte data) {
*(this->db_port) = data;
this->enable();
}
void GraphicsDisplay::instruct(byte instruction) {
digitalWrite(this->rs, LOW);
this->send(instruction);
digitalWrite(this->rs, HIGH);
}
void GraphicsDisplay::flush(void) {
digitalWrite(this->rs, LOW);
digitalWrite(this->rw, HIGH);
*(this->db_ddr) = 0x00;
do {
this->enable();
} while (*(this->db_pin) & (GD_BUSY_MASK | GD_RESET_MASK));
digitalWrite(this->rs, HIGH);
digitalWrite(this->rw, LOW);
*(this->db_ddr) = 0xFF;
}
size_t GraphicsDisplay::write(uint8_t data) {
word raw = data;
raw <<= this->getCursorX() % 8;
this->flush();
this->send(lowByte(raw));
byte high = highByte(raw);
if (high) {
this->flush();
this->send(high);
}
return 1;
}
boolean GraphicsDisplay::seek(unsigned int x, unsigned int y) {
if (!Rectangle::seek(x, y)) {
return false;
}
this->selectChip(x > 63);
this->flush();
this->instruct((y & GD_Y_MASK) | GD_Y);
int page = x / 8;
this->flush();
this->instruct((page & GD_X_MASK) | GD_X);
}
Rectangle::Rectangle(Rectangle *parent, unsigned int width, unsigned int height) : parent(parent), width(width), height(height) {
}
Rectangle *Rectangle::getParent() const {
return this->parent;
}
unsigned int Rectangle::getWidth() const {
return this->width;
}
unsigned int Rectangle::getHeight() const {
return this->height;
}
unsigned int Rectangle::getX() const {
return this->x;
}
unsigned int Rectangle::getY() const {
return this->y;
}
boolean Rectangle::move(unsigned int x, unsigned int y) {
Rectangle *parent = this->getParent();
if (parent == NULL) {
return false;
}
int bytes = (this->getWidth() / 8);
if (this->getWidth() % 8) {
bytes++;
}
// clear
for (int iy = 0; iy < this->getHeight(); iy++) {
parent->seek(this->getX(), this->getY() + iy);
for (int ix = 0; ix <= bytes; ix++) {
parent->write(0x00);
}
}
this->x = x;
this->y = y;
// draw
for (int iy = 0; iy < this->getHeight(); iy++) {
parent->seek(this->getX(), this->getY() + iy);
for (int ix = 0; ix <= bytes; ix++) {
byte data = 0xFF;
if (ix == 0) {
data <<= this->getWidth() % 8;
}
else if (ix == bytes) {
data >>= 8 - (this->getWidth() % 8);
}
parent->write(data);
}
}
}
const Rectangle *Rectangle::detectCollision(int siblingc, const Rectangle *const siblings[]) const {
for (int i = 0; i < siblingc; i++) {
const Rectangle *sibling = siblings[i];
int collidesX = 0;
collidesX |= this->getX() < sibling->getX() + sibling->getWidth();
collidesX |= this->getX() + this->getWidth() < sibling->getX();
int collidesY = 0;
collidesY |= this->getY() < sibling->getY() + sibling->getHeight();
collidesY |= this->getY() + this->getHeight() < sibling->getY();
if (collidesX && collidesY) {
return sibling;
}
}
return NULL;
}
unsigned int Rectangle::getCursorX() const {
Rectangle *parent = this->getParent();
if (parent == NULL) {
return this->getX();
}
return parent->getCursorX() - this->getX();
}
unsigned int Rectangle::getCursorY() const {
Rectangle *parent = this->getParent();
if (parent == NULL) {
return this->getY();
}
return parent->getCursorY() - this->getY();
}
size_t Rectangle::write(uint8_t data) {
Rectangle *parent = this->getParent();
if (parent == NULL) {
return 0;
}
return parent->write(data);
}
boolean Rectangle::seek(unsigned int x, unsigned int y) {
if (x >= this->getWidth() || y >= this->getHeight()) {
return false;
}
Rectangle *parent = this->getParent();
if (parent == NULL) {
this->x = x;
this->y = y;
return true;
}
return parent->seek(x + this->getX(), y + this->getY());
}
boolean Rectangle::seek(unsigned int address) {
address *= 8;
unsigned int y = address / this->getHeight();
unsigned int x = (address % this->getHeight()) * 8;
return this->seek(x, y);
}
#ifndef GraphicsDisplay_h
#define GraphicsDisplay_h 1
#include <Arduino.h>
#define GD_OFF 0x3E // 00111110
#define GD_OFF_MASK 0x01 // 00000001
#define GD_Y 0x40 // 01000000
#define GD_Y_MASK 0x3F // 00111111
#define GD_X 0xB8 // 10111000
#define GD_X_MASK 0x07 // 00000111
#define GD_Z 0xC0 // 11000000
#define GD_Z_MASK 0x3F // 00111111
#define GD_BUSY_MASK 0x01 // 00000001
#define GD_OFF_MASK 0x04 // 00000100
#define GD_RESET_MASK 0x08 // 00001000
class Rectangle : public Print {
public:
Rectangle(Rectangle *parent, unsigned int width, unsigned int height);
Rectangle *getParent() const;
unsigned int getWidth() const;
unsigned int getHeight() const;
unsigned int getX() const;
unsigned int getY() const;
boolean move(unsigned int x, unsigned int y);
const Rectangle *detectCollision(int siblinc, const Rectangle *const siblings[]) const;
virtual unsigned int getCursorX() const;
virtual unsigned int getCursorY() const;
virtual size_t write(uint8_t data);
virtual boolean seek(unsigned int x, unsigned int y);
virtual boolean seek(unsigned int address);
private:
Rectangle *const parent;
const unsigned int width, height;
unsigned int x, y;
};
class GraphicsDisplay : public Rectangle {
public:
GraphicsDisplay(int rs, int rw, int e, volatile byte *db_port, volatile byte *db_pin, volatile byte *db_ddr, int cs0, int cs1, int rst);
void reset();
void enable();
void selectChip(int chip);
void send(byte data);
void instruct(byte instruction);
void flush(void);
size_t write(byte data);
boolean seek(unsigned int x, unsigned int y);
private:
const int rs, rw, e, cs0, cs1, rst;
volatile byte *const db_port, *const db_pin, *const db_ddr;
};
#endif // GraphicsDisplay_h
#include "GraphicsDisplay.h"
#define BALL_WIDTH 2
#define BALL_HEIGHT 2
#define PADDLE_WIDTH 2
#define PADDLE_HEIGHT 16
#define PADDLE_OFFSET 8
#define PADDLE1_X PADDLE_OFFSET
#define PADDLE2_X (WIDTH - PADDLE_OFFSET - 1)
#define UPDATE_RATE 100
#define BUTTON_PCIE PCIE1
#define BUTTON_PCMSK PCMSK1
#define BUTTON_PCINT_VECT PCINT1_vect
#define BUTTON1_PCINT PCINT9
#define BUTTON2_PCINT PCINT10
#define BUTTON1_PIN A1
#define BUTTON2_PIN A2
#define RECT_COUNT 3
#define WIDTH 128
#define HEIGHT 64
int paddle1YDir = -1;
int paddle2YDir = -1;
int paddle1YPos = 40;
int paddle2YPos = 40;
int ballXPos = 64;
int ballYPos = 32;
int ballYDir = -1;
int ballXDir = 1;
GraphicsDisplay disp(8, 9, 10, &PORTD, &PIND, &DDRD, 11, 12, 13);
Rectangle ball(&disp, BALL_WIDTH, BALL_HEIGHT);
Rectangle paddle1(&disp, PADDLE_WIDTH, PADDLE_HEIGHT);
Rectangle paddle2(&disp, PADDLE_WIDTH, PADDLE_HEIGHT);
const Rectangle *const rects[] = { &ball, &paddle1, &paddle2 };
void setup() {
//Buttonpins
pinMode(BUTTON1_PIN, INPUT_PULLUP);
pinMode(BUTTON2_PIN, INPUT_PULLUP);
// Attach pin change interrupts
PCICR |= _BV(BUTTON_PCIE);
BUTTON_PCMSK |= _BV(BUTTON1_PCINT) | _BV(BUTTON2_PCINT);
}
void loop() {
//Moving the ball, checking for colission, adjusting the direction in x and y axis,
//and resetting the game when someone wins
if (!ball.move(ballXPos, ballYPos)) {
ballYDir=ballYDir*(-1);
}
const Rectangle *collision = ball.detectCollision(RECT_COUNT, rects);
if (collision == &paddle1 || collision == &paddle2) {
ballXDir=ballXDir*(-1);
}
if (ballXPos>PADDLE2_X||ballXPos<PADDLE1_X) {
int paddle1YDir = -1;
int paddle2YDir = -1;
int paddle1YPos = 40;
int paddle2YPos = 40;
int ballXPos = 64;
int ballYPos = 32;
int ballYDir = -1;
int ballXDir = 1;
ball.move(ballXPos, ballYPos);
paddle1.move(PADDLE1_X, paddle1YPos);
paddle2.move(PADDLE2_X, paddle2YPos);
delay(500);
}
//----------------------------------------
//Colission detection for paddles, disallowing them to move further
if (!paddle1.move(PADDLE1_X, paddle1YPos)) {
paddle1YDir=0;
}
if (!paddle2.move(PADDLE2_X, paddle2YPos)) {
paddle2YDir=0;
}
//------------------------------------------------------------------
//Increment the positions
ballXPos+=ballXDir;
ballYPos+=ballYDir;
paddle1YPos+=paddle1YDir;
paddle2YPos+=paddle2YDir;
//-----------------------
//Setting the updaterate of the game
delay(UPDATE_RATE);
}
//Functions from the interrupt
ISR(BUTTON_PCINT_VECT) {
paddle1YDir = digitalRead(BUTTON1_PIN) == HIGH ? 1 : -1;
paddle2YDir = digitalRead(BUTTON2_PIN) == HIGH ? 1 : -1;
}
//-------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment