Amikor még gimnáziumba jártam Budapesten olyan 1999 körül, a Corvin moziban volt kirakva egy játéktermi játékgép: The Lost World: Jurassic Park
1997-ben hozta ki a Sega, gondolom az azonos című azonos évben bemutatott Jurassic Park marketingjére ülve.
Suli után sokat játszottunk rajta, nem volt olcsó, ha jól emlékszem 200 forint volt egy zseton hozzá.
A képen a bal oldali masina. Ez a kép amúgy a Savoya parkban készült az azóta már bezárt Arcadia Savoya játékteremben 2023 decemberében. Elvileg ez csak egy kiállítás volt, fix árért az összes géppel lehetett játszani korlátlan ideig.
Szóval nagyon hangulatos volt ez a Jurassic Park Arcade gép. Gondoltam megnézem van-e PC-s változata, és igen volt. Mégpedig az arcade gép eredeti ROM-ját lehet PC-n emulálni. Nagyon megörültem, de egérrel túl könnyű vele játszani. Az eredeti gépen úgynevezett fény pisztolyok voltak. Ahová irányította az ember a pisztolyt, oda tudott lőni. De ez csak a katódsugárcsöves monitorokon működött. Manapság már LCD kijelzők vannak. Erre van egy új megoldás ami gyakorlatilag a Nintendo Wii controllerét használja fegyverként. A tv fölé kell rakni egy infra led fényforrást és a controller infra kamerája ezt lekövetve, egérként is tudjuk használni. Aztán voltak házi megoldások is, csináld magad fénypisztoly, infra kamerával Arduino-val. Na én ezt raktam össze végül, hogy tudjak a plazma tévén játszani vele. A leggazdaságosabban egy Wii controllerrel lehet megoldani, ha van de ekkor is kell az infra led fényforrás. Wii sensor bar-nak hívják. Létezik egy kiegészítő is a Wii kontrollerhez amibe berakva egy pisztoly formát kapunk.
Tehát hozzávalók, ahogyan én csináltam:
- a Farnell-től SEN0158 IR POSITIONING CAMERA, ARDUINO BOARD 85258300
10.000 forint volt
-Arduino Leonardo, ide az Uno nem jó, mert a Leonardo tud csak egeret emulálni
-kartondoboz a pisztoly formához
-nyomógombok a tüzeléshez
-kábelek
-egy 5méteres usb kábel
A megvalósításhoz az ötletet innen vettem és másoltam: (ez két link)
SAMCO DIY Light Gun - Trouble Shooting Sketch (youtube.com)
GitHub - samuelballantyne/IR-Light-Gun: Arduino Library for the SAMCO Arduino Powered IR Light Gun
Íme a végeredmény. A használat, ha rádugtuk a számítógépre, el kell indítani az Arduino IDE-t és a serial monitort. Persze be kell kapcsolni az infra ledeket is. A kamerát az infra ledekre mutatva meg kell nyomni a kalibráló gombot, ami nekem a piros gomb bal oldalon. Utána a tűz gomb 1x, nálam ez az alsó mikrokapcsoló belül. Utána a tv bal felső sarkára célozva újabb tűz gomb, majd a tv bal alsó sarkára célozva újabb tűz gomb. Innentől elvileg egérként tudjuk használni.
Meg kell jegyezzem az én nagy plazma tévémmel nem működik jól mert túl nagy a tv átmérője. Az infra kamera érzékelési szöge pedig elég kicsi. Maga az arduino kód sem hiszem hogy tökéletes nagyon remeg az egérmutató. Egy Wii kontroller valószínű sokkal jobb lenne. A kalibráció során is vannak gondok mert néha csak sokadjára sikerül működésre bírni ha véletlenül túlságosan kifelé célozva nyomjuk meg a tűzgombot, ekkor a kamea nem látja az infra led forrást és rosszul kalobrál.
Arduino kód:
Samco - Arduino Powered IR Light Gun
Go to https://github.com/samuelballantyne for code & instructions.
created June 2019
by Sam Ballantyne
This sample code is part of the public domain.
*/
int positionX[4]; // RAW Sensor Values
int positionY[4];
int oneY = 0; // Re-mapped so left sensor is always read first
int oneX = 0;
int twoY = 0;
int twoX = 0;
int finalX = 0; // Values after tilt correction
int finalY = 0;
int xLeft = 0; // Stored calibration points
int yTop = 0;
int xRight = 0;
int yBottom = 0;
int MoveXAxis = 0; // Unconstrained mouse postion
int MoveYAxis = 0;
int conMoveXAxis = 0; // Constrained mouse postion
int conMoveYAxis = 0;
int count = 4; // Set intial count
int caliPin = A1; // Set Calibration Pin (change to A4 to use ALT Pin)
int leftPin = A2; // Set Left Mouse Pin
int rightPin = A3;
int buttonState1 = 0; // Set Button states
int lastButtonState1 = 0;
int buttonState2 = 0;
int lastButtonState2 = 0;
int buttonState3 = 0;
int lastButtonState3 = 0;
int buttonState4 = 0;
int lastButtonState4 = 0;
int buttonState5 = 0;
int lastButtonState5 = 0;
#include <HID.h> // Load libraries
#include <Wire.h>
#include <AbsMouse.h>
#include <DFRobotIRPosition.h>
DFRobotIRPosition myDFRobotIRPosition;
int res_x = 1920; // Put your screen resolution width here
int res_y = 1080; // Put your screen resolution height here
void setup() {
Serial.begin(9600); // For debugging (make sure your serial monitor has the same baud rate)
AbsMouse.init(res_x, res_y);
pinMode(caliPin, INPUT_PULLUP); // Set pin modes
pinMode(leftPin, INPUT_PULLUP);
pinMode(rightPin, INPUT_PULLUP);
myDFRobotIRPosition.begin(); // Start IR Camera
AbsMouse.move((res_x / 2), (res_y / 2)); // Set mouse position to centre of the screen
delay(500);
}
void loop() {
if (count > 3) {
getPosition();
mouseButtons();
PrintResults();
go();
}
/* ------------------ START/PAUSE MOUSE ---------------------- */
else if (count > 2 ) {
skip();
mouseCount();
}
/* ---------------------- TOP LEFT --------------------------- */
else if (count > 1 ) {
AbsMouse.move(300, 200);
mouseCount();
getPosition();
reset();
xLeft = finalX;
yTop = finalY;
PrintResults();
}
/* -------------------- BOTTOM RIGHT ------------------------- */
else if (count > 0 ) {
AbsMouse.move((res_x - 300), (res_y - 200));
mouseCount();
getPosition();
reset();
xRight = finalX;
yBottom = finalY;
PrintResults();
}
/* ---------------------- LET'S GO --------------------------- */
else {
AbsMouse.move(conMoveXAxis, conMoveYAxis);
mouseButtons();
getPosition();
MoveXAxis = map (finalX, xLeft, xRight, 300, (res_x - 300));
MoveYAxis = map (finalY, yTop, yBottom, 200, (res_y - 200));
conMoveXAxis = constrain (MoveXAxis, 0, res_x);
conMoveYAxis = constrain (MoveYAxis, 0, res_y);
PrintResults();
reset();
}
}
/* ----------------------------------------------- */
/* --------------------------- METHODS ------------------------- */
/* ----------------------------------------------- */
void getPosition() { // Get tilt adjusted position from IR postioning camera
myDFRobotIRPosition.requestPosition();
if (myDFRobotIRPosition.available()) {
for (int i = 0; i < 4; i++) {
positionX[i] = myDFRobotIRPosition.readX(i);
positionY[i] = myDFRobotIRPosition.readY(i);
}
if (positionX[0] > positionX[1]) {
oneY = positionY[0];
oneX = positionX[0];
twoY = positionY[1];
twoX = positionX[1];
}
else if (positionX[0] < positionX[1]) {
oneY = positionY[1];
oneX = positionX[1];
twoY = positionY[0];
twoX = positionX[0];
}
else {
oneY = 1023;
oneX = 0;
twoY = 1023;
twoX = 0;
}
finalX = 512 + cos(atan2(twoY - oneY, twoX - oneX) * -1) * (((oneX - twoX) / 2 + twoX) - 512) - sin(atan2(twoY - oneY, twoX - oneX) * -1) * (((oneY - twoY) / 2 + twoY) - 384);
finalY = 384 + sin(atan2(twoY - oneY, twoX - oneX) * -1) * (((oneX - twoX) / 2 + twoX) - 512) + cos(atan2(twoY - oneY, twoX - oneX) * -1) * (((oneY - twoY) / 2 + twoY) - 384);
}
else {
Serial.println("Device not available!");
}
}
void go() { // Setup Start Calibration Button
buttonState1 = digitalRead(caliPin);
if (buttonState1 != lastButtonState1) {
if (buttonState1 == LOW) {
count--;
}
else { // do nothing
}
delay(50);
}
lastButtonState1 = buttonState1;
}
void mouseButtons() { // Setup Left, Right & Middle Mouse buttons
buttonState2 = digitalRead(leftPin);
buttonState3 = digitalRead(rightPin);
if (buttonState2 != lastButtonState2) {
if (buttonState2 == LOW) {
AbsMouse.press(MOUSE_LEFT);
}
else {
AbsMouse.release(MOUSE_LEFT);
}
delay(10);
}
if (buttonState3 != lastButtonState3) {
if (buttonState3 == LOW) {
AbsMouse.press(MOUSE_RIGHT);
}
else {
AbsMouse.release(MOUSE_RIGHT);
}
delay(10);
}
lastButtonState2 = buttonState2;
lastButtonState3 = buttonState3;
}
void mouseCount() { // Set count down on trigger
buttonState2 = digitalRead(leftPin);
if (buttonState2 != lastButtonState2) {
if (buttonState2 == LOW) {
count--;
}
else { // do nothing
}
delay(10);
}
lastButtonState2 = buttonState2;
}
void reset() { // Pause/Re-calibrate button
buttonState1 = digitalRead(caliPin);
if (buttonState1 != lastButtonState1) {
if (buttonState1 == LOW) {
count = 3;
delay(50);
}
else { // do nothing
}
delay(50);
}
lastButtonState1 = buttonState1;
}
void skip() { // Unpause button
buttonState1 = digitalRead(caliPin);
if (buttonState1 != lastButtonState1) {
if (buttonState1 == LOW) {
count = 0;
delay(50);
}
else { // do nothing
}
delay(50);
}
lastButtonState1 = buttonState1;
}
void PrintResults() { // Print results for debugging
Serial.print("RAW: ");
Serial.print(finalX);
Serial.print(", ");
Serial.print(finalY);
Serial.print(" Count: ");
Serial.print(count);
Serial.print(" Calibration: ");
Serial.print(xLeft);
Serial.print(", ");
Serial.print(yTop);
Serial.print(", ");
Serial.print(xRight);
Serial.print(", ");
Serial.print(yBottom);
Serial.print(" Position: ");
Serial.print(conMoveXAxis);
Serial.print(", ");
Serial.println(conMoveYAxis);
}