Space Invaders on RasPi With OLED and Capacitive Touch
by dsberman in Circuits > Raspberry Pi
1091 Views, 0 Favorites, 0 Comments
Space Invaders on RasPi With OLED and Capacitive Touch
This project implements Capacitive Touch to a Space Invaders game that runs on a Raspberry Pi.
Things Used in This Project
Hardware components
- Raspberry Pi 2 Model B x 1
With Power Supply and SD card loaded with Raspbian - XinaBox OD01 x 1
- XinaBox BR01 x 1
- XinaBox SH01 x 1
- XinaBox XC10 x 1
Story
With no requirement for soldering, wiring or any specific hardware knowledge, we click together a Space Invaders game played on a RasPi with a OLED display and a Capacitative Touch panel.
Watch this video first - it first shows how the hardware is clicked together.
Click together a Space Invaders game for the Raspberry Pi
Preparation
- Click together the hardware as per the above video.
- Install the LUMA OLED library, by following these instructions: https://luma-oled.readthedocs.io/en/latest/intro.html and https://github.com/rm-hull/luma.oled. You can also watch this Hackster Project, which might help you with the LUMA OLED installation: https://www.hackster.io/gotfredsen/raspi-video-to-oled-a470e2.
Modify Invaders.py Example
- The attached code is the complete code with modification. It is only been modified in the beginning with this code:
# Cap Touch modification Start import sys import smbus2 bus = smbus2.SMBus(1) DEVICE_ADDRESS = 0x28 CAP_TOUCH_GENERAL_STATUS = 0x02 CAP_TOUCH_SENSOR_INPUT_STATUS = 0x03 bus.write_byte_data(DEVICE_ADDRESS, 0x27, 0x0) bus.write_byte_data(DEVICE_ADDRESS, 0x21, 0x39) bus.write_byte_data(DEVICE_ADDRESS, 0x0, 0x0) # Cap Touch modification End
- And in the end with this code:
# Cap Touch Code Start touch_type = bus.read_byte_data(DEVICE_ADDRESS,CAP_TOUCH_GENERAL_STATUS) if touch_type == 0x01: button = bus.read_byte_data(DEVICE_ADDRESS,CAP_TOUCH_SENSOR_INPUT_STATUS) if button == 0x01: sys.exit("User exit!") if button == 0x20: plyr.update(1) if button == 0x08: plyr.shoot() plyr.update(0) if button == 0x10: plyr.update(-1) bus.write_byte_data(DEVICE_ADDRESS, 0x0, 0x0) # ai_logic_shoot(army, plyr) # ai_logic_move(army, plyr, rows) # Cap Touch Code End
- Now run the code: ./invaders.py or python invaders.py
Code
invaders.py Python
This is the code, originally from Richard Hull's LUMA examples:
#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2014-17 Richard Hull and contributors # See LICENSE.rst for details. # PYTHON_ARGCOMPLETE_OK # Cap Touch by XinaBox """ Space Invaders demo. Ported from: https://gist.github.com/TheRayTracer/dd12c498e3ecb9b8b47f#file-invaders-py """ import os.path import time import random from demo_opts import get_device from PIL import Image from luma.core.render import canvas from luma.core.sprite_system import framerate_regulator # Cap Touch modification Start import sys import smbus2 bus = smbus2.SMBus(1) DEVICE_ADDRESS = 0x28<br>CAP_TOUCH_GENERAL_STATUS = 0x02 CAP_TOUCH_SENSOR_INPUT_STATUS = 0x03 bus.write_byte_data(DEVICE_ADDRESS, 0x27, 0x0) bus.write_byte_data(DEVICE_ADDRESS, 0x21, 0x39) bus.write_byte_data(DEVICE_ADDRESS, 0x0, 0x0) # Cap Touch modification End arrow = [0x04, 0x02, 0x01, 0x02, 0x04] alien1 = [0x4C, 0x1A, 0xB6, 0x5F, 0x5F, 0xB6, 0x1A, 0x4C] alien2 = [0x18, 0xFD, 0xA6, 0x3C, 0x3C, 0xA6, 0xFD, 0x18] alien3 = [0xFC, 0x98, 0x35, 0x7E, 0x7E, 0x35, 0x98, 0xFC] ARMY_SIZE_ROWS = 2 ARMY_SIZE_COLS = 6 class bullet(object): def __init__(self, x, y): self.x = x self.y = y self.alive = False def render(self, draw): if self.alive: draw.line((self.x, self.y, self.x, self.y + 2), fill="white") def reset(self, x, y): self.x = x self.y = y self.alive = True return def update(self, direction): if self.alive: self.y = self.y + (direction * 4) if self.y < 10: self.alive = False class player(object): def __init__(self): self.x = 48 self.y = 54 self.bullets = [bullet(0, 0) for _ in range(4)] def render(self, draw): for i in range(len(arrow)): line = arrow[i] for j in range(3): if line & 0x1: draw.point((self.x - 2 + i, self.y + j), fill="white") line >>= 1 for bullet in self.bullets: bullet.render(draw) def update(self, direction): t = self.x + (direction * 2) if t > 4 and t < 92: self.x = t for bullet in self.bullets: bullet.update(-1) def shoot(self): for bullet in self.bullets: if not bullet.alive: bullet.reset(self.x, self.y) break class invader(object): def __init__(self, minx, maxx, x, y): self.x = x self.y = y self._direction = 1 self.alive = True self.score = 10 self._minx = minx self._maxx = maxx return def render(self, draw): if self.alive: for i in range(len(alien2)): line = alien2[i] for j in range(8): if line & 0x1: draw.point((self.x - 4 + i, self.y - 4 + j), "green") line >>= 1 def update(self): invaded = False if self.alive: t = self.x + self._direction if t > self._minx and t < self._maxx: self.x = self.x + self._direction else: self._direction = self._direction * -1 self.y = self.y + 2 if self.y > 44: invaded = True return invaded class army(object): def __init__(self): self.invaded = False self.invaders = [] for i in range(ARMY_SIZE_ROWS): for j in range(ARMY_SIZE_COLS): minx = 4 + (j * 12) maxx = 30 + (j * 12) x = 4 + (j * 12) y = 14 + (i * 12) self.invaders.append(invader(minx, maxx, x, y)) def render(self, draw): for invader in self.invaders: invader.render(draw) def update(self, bullets): for invader in self.invaders: if invader.update(): self.invaded = True for invader in self.invaders: if invader.alive: for bullet in bullets: if bullet.alive: t = (invader.x - bullet.x) * (invader.x - bullet.x) + (invader.y - bullet.y) * (invader.y - bullet.y) # if point is in circle if t < 25: # 5 * 5 = r * r invader.alive = False bullet.alive = False def size(self): size = 0 for invader in self.invaders: if invader.alive: size += 1 return size def score(self): score = 0 for invader in self.invaders: if not invader.alive: score += invader.score return score def ai_logic_shoot(army, plyr): for invader in army.invaders: if invader.alive: if plyr.x > (invader.x - 2) and plyr.x < (invader.x + 2): if random.random() < 0.75: plyr.shoot() return def ai_logic_move(army, plyr, rows): for i in rows: invader = army.invaders[i] if invader.alive: if plyr.x < invader.x: plyr.update(1) return elif plyr.x > invader.x: plyr.update(-1) return i += 1 if __name__ == '__main__': device = get_device() if device.width < 96 or device.height < 64: raise ValueError("Unsupported mode: {0}x{1}".format(device.width, device.height)) regulator = framerate_regulator() plyr = player() army = army() rows = random.sample(range(12), 12) img_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'images', 'splash.bmp')) splash = Image.open(img_path) \ .transform((device.width, device.height), Image.AFFINE, (1, 0, 0, 0, 1, 0), Image.BILINEAR) \ .convert(device.mode) try: # Double buffering in pygame? device.display(splash) device.display(splash) time.sleep(3) device.clear() while not army.invaded and army.size() > 0: with regulator: with canvas(device) as draw: draw.line((0, 61, 95, 61), fill="white") draw.line((0, 63, 95, 63), fill="white") # Cap Touch Code Start touch_type = bus.read_byte_data(DEVICE_ADDRESS,CAP_TOUCH_GENERAL_STATUS) if touch_type == 0x01: button = bus.read_byte_data(DEVICE_ADDRESS,CAP_TOUCH_SENSOR_INPUT_STATUS) if button == 0x01: sys.exit("User exit!") if button == 0x20: plyr.update(1) if button == 0x08: plyr.shoot() plyr.update(0) if button == 0x10: plyr.update(-1) bus.write_byte_data(DEVICE_ADDRESS, 0x0, 0x0) # ai_logic_shoot(army, plyr) # ai_logic_move(army, plyr, rows) # Cap Touch Code End army.update(plyr.bullets) army.render(draw) plyr.render(draw) draw.text((8, 0), text="Score: {0}".format(army.score()), fill="blue") # Double buffering in pygame? for i in range(2): with canvas(device) as draw: if army.size() == 0: draw.text((27, 28), text="Victory", fill="blue") else: draw.text((30, 28), text="Defeat", fill="red") time.sleep(5) except KeyboardInterrupt: pass