Arduino Skylanders
Skylanders is a game where you place real life figurines on a portal to ‘teleport’ them in game. I made a similar set up with Arduino!
Downloads
Supplies
· Arduino UNO
· Wires
· RFID-RC522 NFC Kit
· LED and resistor (220 ohm) (optional)
· A box (optional)
· Unity Game Engine
· 3D model (printed and digital)
Set-Up Reader
First set up the NFC reader. I did it according to the image.
Add LED
I added a LED to make it more clear for myself when the chip was being read. So I did that according the scheme in the image.
Arduino Code
As for the code. I first wrote code on to make the reader work. I kept checking in the Serial reader if it gives me the notifications. Also to see the number of the chip you’re working with.
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
Serial.println("Scan an NFC tag");
}
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// Show UID on serial monitor
Serial.print("UID tag :");
String content = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
Serial.println();
delay(1000);
}
Then I added the LED portion:
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 10
#define RST_PIN 9
const int ledPin = 7;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
Serial.println("Scan an NFC tag");
pinMode(ledPin, OUTPUT);
}
void loop() {
// Look for new cards
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.print("UID tag :");
String content = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
Serial.println(); // Ensure each message ends with a newline character
Serial.println(content); // Send the UID again in a simpler format
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Unity
Make a project in Unity. Add an asset pack called Ardity.
Add the SerialController script Prefab to your scene and make sure the right Port is added in the Inspector.
Then create a scene with a Plane, your character model and an Empty Game Object called SpawnPoint.
Create a new Script NFC reader. Write the following code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NFCReader : MonoBehaviour
{
public SerialController serialController;
public GameObject characterPrefab; // Reference to the character prefab
public Transform spawnPoint; // Where the character will be spawned
private GameObject spawnedCharacter; // Track the spawned character instance
private bool hasSpawned; // Flag to track if the character has been spawned
void Start()
{
serialController = GameObject.Find("SerialController").GetComponent<SerialController>();
}
void Update()
{
string message = serialController.ReadSerialMessage();
if (message == null || hasSpawned)
return;
Debug.Log("Raw message received: " + message);
ProcessData(message);
}
void ProcessData(string data)
{
// Extract the UID part from the message
string trimmedData = ExtractUID(data);
Debug.Log("Extracted UID: " + trimmedData);
// Check if the UID matches the expected UID
if (trimmedData == "UIDCHIPCODE" && !hasSpawned) // Replace with your NFC tag UID
{
SpawnCharacter();
hasSpawned = true; // Set the flag to true after spawning
}
else
{
Debug.LogWarning("Unexpected UID: " + trimmedData);
}
}
void SpawnCharacter()
{
// Spawn the character prefab at the spawn point
spawnedCharacter = Instantiate(characterPrefab, spawnPoint.position, spawnPoint.rotation);
Debug.Log("Character spawned: " + spawnedCharacter.name);
spawnedCharacter.tag = "Player"; // Assigning "Player" tag to the spawned character
// Attach the CameraFollow script to the main camera and set the target to the spawned character
Camera.main.gameObject.AddComponent<CameraFollow>();
CameraFollow cameraFollowScript = Camera.main.GetComponent<CameraFollow>();
if (cameraFollowScript != null)
{
cameraFollowScript.SetTarget(spawnedCharacter.transform);
}
else
{
Debug.LogError("CameraFollow script not found on main camera.");
}
}
string ExtractUID(string data)
{
// Find the index of the colon and extract the UID part
int colonIndex = data.IndexOf(':');
if (colonIndex >= 0 && colonIndex + 1 < data.Length)
{
// Extract substring after the colon and remove spaces
string uidPart = data.Substring(colonIndex + 1).Replace(" ", "").Trim();
return uidPart;
}
return data.Replace(" ", "").Trim();
}
}
This script makes sure your character spawned when the card reader reads the script. Change the UIDCHIPCODE to the name of your chip that appeared in the Serial reader earlier. We use the UIDs, so we could spawn more characters with different chips.
Don't forget to assign your Spawnpoint and Character model in the inspector.
You'll see that the model will clone itself. If you don't want to see a döppelganger of your character in the scene, just move it far away so it will be out of sight.
Finishing Touches
To make the character move around, add a PlayerController Script to your original character with Rigidbody and a collider attached.
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 6.0f;
public float jumpHeight = 1.5f;
public float gravity = -9.81f;
public float turnSmoothTime = 0.1f;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
private float turnSmoothVelocity;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f; // Ensure the character sticks to the ground
}
Move();
Jump();
}
void Move()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 direction = new Vector3(moveHorizontal, 0f, moveVertical).normalized;
if (direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
controller.Move(moveDirection * speed * Time.deltaTime);
}
}
void Jump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
Here's an example of how to make your character move around.
Other things you could add are a camera that follows the player around. You just add that script to the original character model as well. Here's mine:
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public float smoothSpeed = 0.125f;
public Vector3 offset;
private Transform target; // Target transform for the camera to follow
void LateUpdate()
{
if (target != null)
{
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
transform.LookAt(target);
}
}
public void SetTarget(Transform newTarget)
{
target = newTarget;
}
}
Lastly, I added a bit of an environment (assets from Polytope Studio), and glued the chip to the bottom of my model... and done!