coFarm
Made by Judy Mai, Nathan and Aliya Blackwood
Made by Judy Mai, Nathan and Aliya Blackwood
A collaborative farming game that brings out the best and worst of its players.
Created: December 1st, 2015
This collaborative game aims to create a shared interactive experience in a farming environment where all players share limited resources, such as seeds and water.
Players can work together to help each other out and further each other's progress...or alternatively, choose to keep the resources for themselves and sabotage other players for a higher personal score.
What would you do? Whether you choose to be collaborative or competitive is up to you.
While traditionally, augmented reality experiences are more individual and isolated playgrounds, we hoped to expand that experience so that multiple people can experience and impact the same virtual space.
For example, whenever people experience augmented reality, they're simply looking through an image on their own phones, and it's very individual. We wanted everyone to be working together in one single virtual environment where users can interact with each other in a playful, perhaps competitive manner.
Our original goal was to create a unified augmented reality experience that brings out the best and worst of its players. (The "best" in the sense where they collaborate and help each other, and the "worst" in the sense that they could completely sabotage other player for their own benefit).
We hope to create a collaborative game in which users share tools and resources to grow crops on virtual plots of land using Makey Makey devices and augmented reality through a projection.
Users will grow plants by touching a surface where the user interface is projected. The elements for interaction will also double as image-targets for the augmented reality, where a webcam will pick up the locations of the targets and project 3d crops on a separate television. This is a secondary and non-informative screen, but it enhances the experience for our users. The main interface will be the surface the users are interacting with, where they will grow seeds, water plants, harvest crops, etc.
We also plan to use the Makey-Makey to make the installation more permanently interactive. When a circuit is created with the Makey Makey, it registers as a certain input in the computer, such as an "g" or a "h". We can use these inputs to allow multiple users play the same game.
The Makey Makey device will be wired to preset panels on the surface of the table, creating touch zones for the game itself. We will use 2 Makey Makeys in together with a laptop to maintain game state and update the target images/user interface. Essentially this will allow us to make a giant touch surface using circuits as "buttons".
Cooperative games, especially those like Farmville and other social games, don't often give users much of a moral decision during gameplay. Users operate together in order to further each other's progress and to enhance the experience overall by sharing resources.
In coFarm, users will all be sharing resources such as money for seeds, water for crops, and tools for interacting with their plots of land. However, each piece of land will have reputation and experience that contribute to an individual user's score in addition to team success. If a particular player's plot is given a larger share of the water, its crops will be worth more and its land worth more as well. In addition, other players' plots doing poorly is beneficial, to a certain extent, to any given player in that their plot is more relatively reputable -- and reputation is everything for each farmer.
So we will give the users the tools to burn. Not just their own plots but the plots of others. It will definitely harm the other player's plot, and the fire may spread (and it will be a waste of shared resources), but it will guarantee a higher relative reputation for the other players.
Somewhat like the Goodbye, World project in the Inter-play pool, the projects we're looking at pose the player or viewer as God-like or in a position to control nature. Below is a video of an interactive game book that looks very similar to the experience that we hope to create. We would love to combine the interactivity of Goodbye, World with the aesthetic feel and immersive-ness of the game book shown below.
The physical layout is a very difficult component of coFarm. We need to include an incredibly complex technical setup in a small area while keeping the bar-of-entry low. Below, we've included sketches of our intended final setup using the television in the front of the classroom, a table rigged with touch zones, two Makey Makeys, a laptop, and a ceiling-mounted projector.
We had very specific constraints in mind for the game, so we created it from scratch with JavaScript, HTML, and CSS. Nathan created the site to accept keyboard inputs only -- as the makey makeys mimic keyboards when plugged into USB ports. We designed a touch-centric interface but used only letters a-u to manipulate the game state.
Below is an early render with an attempt to map out touch regions.
As the game progressed, it changed wildly -- we saw new opportunities to create a more interesting experience for our users and took new paths for shared resources and time constraints. We made the game modularly when coding it so that adding a new plant type would be a few lines of code and so that we could adjust the game for balance along the way. Below is an excerpt from the finished game logic (all original code).
var inheritsFrom = function(child, parent) {
child.prototype = Object.create(parent.prototype);
}
var Crop = function($farm) {
this.wet = 100; //0-100
this.mature = 0; //cycles to maturity
this.maxMature = 40;
this.stage = 0;
this.$farm = $farm;
};
//called once every updatejjj
Crop.prototype.age = function() {
if (this.wet == 1) {
this.$farm.find('.targetmessage').html('Dried out!');
this.$farm.removeClass('harvest').addClass('dirt');
this.wet = 0;
this.wet = 0;
} else if (this.wet > 1) {
this.wet -= 0.7;
this.mature += 1;
var progressWidth = (this.mature/this.maxMature)*50+50*(this.stage);
if (this.stage > 1) progressWidth = (this.mature/this.maxMature)*100;
if (this.stage > 2) progressWidth = 0;
this.$farm.find('.progressbar').css('width', progressWidth + '%');
if (this.mature >= this.maxMature) {
this.mature = 0;
this.stage++;
console.log("stage "+this.stage);
if (this.stage == 2) {
console.log("TO STAGE 2");
//harvest time?
this.$farm.addClass('harvest');
this.$farm.find('.targetmessage').html('Harvest Now!');
} else if (this.stage == 3) {
console.log("TO STAGE 3");
this.$farm.find('.targetmessage').html('Spoiled!');
this.$farm.removeClass('harvest').addClass('dirt');
this.wet = 0;
}
}
}
}
Crop.prototype.water = function() {
if (this.wet && this.stage < 3)
this.wet = Math.min(this.wet+4, 100);
}
Crop.prototype.display = function() {
//correct image
var state = (this.wet == 0) ? 'dead' : (this.wet < 50 ? 'dry' : 'normal');
if (this.wet == 50) this.$farm.find('.targetmessage').html('Water Me!');
this.$farm.find('.target').attr('src', 'img/' + this.images[state][Math.min(2,this.stage)]);
this.$farm.find('.waterbar').css('width', (this.wet*3.2)+'px');
}
var Tomato = function($farm) {
Crop.apply(this, [$farm]);
this.price = 10;
this.sellPrice = 50;
this.images = {
normal: ['growtomato1.png.jpg','growtomato2.png.jpg','growtomato3.png.jpg'],
dry: ['watermetomato1.png.jpg','watermetomato2.png.jpg','watermetomato3.png.jpg'],
dead: ['deadtomato1.png.jpg','deadtomato2png.jpg','deadtomato3.png.jpg']
};
}
inheritsFrom(Tomato, Crop);
var Oat = function($farm) {
Crop.apply(this, [$farm]);
this.price = 25;
this.sellPrice = 70;
this.maxmature = 60;
this.images = {
normal: ['growoat1.png.jpg','growoat2rect.jpg','growoat3rect.jpg'],
dry: ['watermeoat1.png.jpg','watermeoat2.png.jpg','watermeoat3.png.jpg'],
dead: ['deadoat2rect.jpg','deadoat2rect.jpg','deadoat3rect.jpg']
};
}
inheritsFrom(Oat, Crop);
var Peach = function($farm) {
Crop.apply(this, [$farm]);
this.price = 110;
this.sellPrice = 250;
this.maxMature = 150;
this.images = {
normal: ['growpeach1.jpg','growpeach2.jpg','growpeach3.jpg'],
dry: ['drypeachrect1.jpg','drypeachrect2.jpg','drypeachrect3.jpg'],
dead: ['deadpeachrect.jpg','deadpeach2rect.jpg','deadpeach3rect.jpg']
};
}
inheritsFrom(Peach, Crop);
var Farm = function(parent) {
this.crop = null;
this.$el = $('<div class="farm dirt"></div>');
this.money = 50;
console.log(this.$el);
parent.append(this.$el);
this.$el.append('<img src="img/dirt.png" class="target" />' +
'<div class="targetmessage"></div>' +
'<div class="progressbar"></div>' +
'<div class="waterbar"></div>')
.append('<div class="menu">' +
'<div class="menu-left"><img src="img/oatspreview.PNG" /></div>' +
'<div class="menu-middle"><img src="img/tomatopreview.PNG" /></div>' +
'<div class="menu-right"><img src="img/peachpreview.PNG" /></div>' +
'</div>')
.append('<div class="plough"><img src="img/hoe.jpg" /></div>')
.append('<div class="harvest-button"><img src="img/harvest.png" /></div>')
.append('<div class="money">$'+this.money.toFixed(2)+'</div>');
};
Farm.prototype.age = function() {
if (this.crop != null) {
this.crop.age()
this.crop.display(this.$el.find('.target'), this.$el.find('.waterbar'));
}
};
Farm.prototype.water = function() {
if (this.crop != null) {
this.crop.water();
}
}
Farm.prototype.plant = function(crop) {
if (this.money >= crop.price) {
this.money -= crop.price;
this.countMoney();
this.crop = crop;
this.$el.removeClass('plowed').find('.menu').removeClass('seed');
this.crop.display(this.$el.find('.target'), this.$el.find('.waterbar'));
} else {
this.$el.find('.money').css('color','red');
var obj = this;
setTimeout(function() {
obj.$el.find('.money').css('color','white');
}, 500);
}
}
Farm.prototype.countMoney = function() {
this.$el.find('.money').html('$' + this.money.toFixed(2));
}
var Game = function() {
this.farms = [];
for (var i = 0; i < settings.numPlayers; i++) {
this.farms.push(new Farm($("#farms")));
}
this.header = new Header($("#header"));
this.inputBuffer = {};
this.inMessage = false;
this.truck = new Truck($("#truck"));
console.log(this.truck);
this.time = 180;
this.countMoney();
$("#countdown").html("Time: "+this.time.toFixed(1));
this.message("Press any key to begin!");
var obj = this;
$(window).keypress(function() {
$(window).unbind();
obj.start();
});
}
Game.prototype.message = function(text) {
$("#message").html(text).css('display', 'block');
$("#message-bg").css('opacity', '0.5').css('display', 'block');
}
Game.prototype.endMessage = function() {
$("#message").css('display', 'none');
$("#message-bg").css('opacity', '0').css('display', 'none');
}
Game.prototype.start = function() {
var obj = this;
this.endMessage();
$(window).keypress(function(event) {
obj.input(event.which);
});
var gameInterval = setInterval(function() {
obj.farms[obj.header.activeFarm()].water();
for (var i = 0; i < obj.farms.length; i++) {
obj.farms[i].age();
}
obj.time = Math.max(0, Math.round(obj.time*10 - 1)/10);
if (obj.time == 0) {
$(window).unbind();
clearInterval(gameInterval);
var maxPlayer = 0;
var maxScore = 0;
for (var i = 0; i < 4; i++) {
if (obj.farms[i].money > maxScore) {
maxScore = obj.farms[i].money;
maxPlayer = i+1;
}
}
obj.message("Time's Up!<br/>Group Score: " + obj.countMoney()
+ "<br/>Player " + maxPlayer + " has high score.<br/>" +
"Press any key to restart."
);
setTimeout(function() {
$(window).keypress(function() {
$(window).unbind();
$(window).keypress(function() {
location.reload();
});
});
}, 2000);
}
$("#countdown").html("Time: " + obj.time.toFixed(1));
}, 100);
}
Game.prototype.middle = function(farmIndex) {
var f = this.farms[farmIndex];
var $farm = f.$el;
if ($farm.is('.dirt')) {
//ploughing
f.crop = null;
$farm.removeClass('dirt').addClass('plowed');
$farm.find('.target').attr('src', 'img/dirt.png');
$farm.find('.targetmessage').html('');
$farm.find('.progressbar').css('width', '0');
this.truck.showMenu();
} else if ($farm.is('.harvest')) {
//time to harvest!
f.money += f.crop.sellPrice;
$farm.find('.progressbar').css('width', '0');
$farm.removeClass('harvest').addClass('dirt');
f.crop = null;
$farm.find('.target').attr('src', 'img/dirt.png');
$farm.find('.targetmessage').html('');
f.countMoney();
this.countMoney();
} else if ($farm.is('.plowed') && $farm.find('.menu').is('.seed')) {
//seed!!
f.plant(new Tomato($farm));
this.countMoney();
}
}
Game.prototype.left = function(farmIndex) {
var $farm = this.farms[farmIndex].$el;
if ($farm.is('.plowed') && $farm.find('.menu').is('.seed')) {
this.farms[farmIndex].plant(new Oat($farm));
this.countMoney();
}
}
Game.prototype.right = function(farmIndex) {
var $farm = this.farms[farmIndex].$el;
if ($farm.is('.plowed') && $farm.find('.menu').is('.seed')) {
this.farms[farmIndex].plant(new Peach($farm));
this.countMoney();
}
}
Game.prototype.countMoney = function() {
var money = 0;
for (var i = 0; i < 4; i++) {
money += this.farms[i].money;
}
$("#money").html('Group Funds: $' + money.toFixed(2));
return money;
}
Game.prototype.input = function(ch) {
if (!this.inputBuffer[ch]) {
this.inputBuffer[ch] = 1;
var obj = this;
var commands = {
"a": function() { obj.truck.to(1, 0); },
"b": function() { obj.truck.to(0, 1); },
"c": function() { obj.truck.to(2, 1); },
"d": function() { obj.truck.to(1, 2); },
"e": function() { obj.truck.to(3, 2); },
"f": function() { obj.truck.to(2, 3); },
"g": function() { obj.header.switchGate('top'); },
"h": function() { obj.header.switchGate('left'); },
"i": function() { obj.header.switchGate('right'); },
"j": function() { obj.left(0); },
"k": function() { obj.middle(0); },
"l": function() { obj.right(0); },
"m": function() { obj.left(1); },
"n": function() { obj.middle(1); },
"o": function() { obj.right(1); },
"p": function() { obj.left(2); },
"q": function() { obj.middle(2); },
"r": function() { obj.right(2); },
"s": function() { obj.left(3); },
"t": function() { obj.middle(3); },
"u": function() { obj.right(3); },
}
console.log(commands[String.fromCharCode(ch)]);
commands[String.fromCharCode(ch)]();
setTimeout(function() {
obj.inputBuffer[ch] -= 1;
}, 100);
} else {
//reset buffer as if just pressed
}
}
var Truck = function($el) {
this.pos = 0;
this.$el = $el;
this.isMoving = false;
}
Truck.prototype.to = function(pos, from) {
if (!this.isMoving && this.pos == from) {
this.pos = pos;
this.moving();
}
}
Truck.prototype.moving = function() {
console.log('moving...');
this.$el.css('margin-left', (this.pos*320)+'px');
this.isMoving = true;
this.$el.addClass('moving');
$(".menu").removeClass('seed');
var obj = this;
setTimeout(function() {
obj.isMoving = false;
obj.$el.removeClass('moving');
obj.showMenu();
}, 1000);
}
Truck.prototype.showMenu = function() {
var $curPlot = $(".farm:nth-child("+(this.pos+1)+")");
if ($curPlot.is('.plowed')) {
var $m = $curPlot.find('.menu');
$m.addClass('seed');
}
}
var Header = function($el) {
this.$el = $el;
this.canvas = this.$el[0];
this.context = this.canvas.getContext('2d');
this.gatePos = {top:1,left:1,right:1}; //1:right, 0:left
this.createRiverbed();
};
Header.prototype.activeFarm = function() {
return (this.gatePos.top ? 1-this.gatePos.left : (3 - this.gatePos.right));
}
Header.prototype.switchGate = function(gate) {
this.gatePos[gate] = 1 - this.gatePos[gate];
this.createRiverbed();
}
Header.prototype.createRiverbed = function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.beginPath();
this.context.moveTo(640, -10);
this.context.lineWidth = 30;
var curves = {
curve: [610, 100, 670, 160, 640, 280],
left : {
curve: [520, 390, 400, 60, 300, 210],
left : {
curve: [250, 300, 100, 300, 100, 400]
},
right: {
curve: [270, 250, 300, 300, 420, 420]
}
},
right: {
curve: [650, 450, 850, 200, 1000, 260],
left : {
curve: [1050, 350, 850, 350, 780, 410]
},
right: {
curve: [1100, 300, 1150, 350, 1150, 400]
}
}
};
var obj = this;
function drawCurve(i, color) {
obj.context.beginPath();
obj.context.lineWidth = 30;
obj.context.strokeStyle = color;
obj.context.moveTo(640, -10);
obj.context.bezierCurveTo.apply(obj.context, curves.curve);
var curCurve = (i < 2) ? curves.left : curves.right;
obj.context.bezierCurveTo.apply(obj.context, curCurve.curve);
curCurve = (i % 2) ? curCurve.right : curCurve.left;
obj.context.bezierCurveTo.apply(obj.context, curCurve.curve);
obj.context.stroke();
obj.context.closePath();
}
for (var i = 0; i < 4; i++) {
if (i != this.activeFarm()) {
drawCurve(i, '#552500');
}
}
drawCurve(this.activeFarm(), '#3080e4');
var gates = {
top: {
pos:[ 640, 280],
left: [640, 260],
right: [660, 280],
}, left: {
pos:[ 290, 280],
left: [290, 250],
right: [300, 250],
}, right: {
pos:[1010, 300],
left: [990, 290],
right: [1010, 290]
}
};
};
var settings = {
numPlayers : 4
};
$(function() {
new Game();
});
Click to Expand
We will have three plants. Each plant will have three stages: bud, small plant, and fully grown. Each stage also has different states: healthy, needs watering, and dead, for a total of 9 models and trigger images for each plant.
We'll be using oats(which will grow the quickest and cost the cheapest), cherry tomatoes, and peaches (which will take longest to grow and cost the most).
These are the 3D models we'll be using, as well as a screenshot of some of the stages. We can modify the colors of the leaves and make them wilt to symbolize that it needs watering, and its clear from the sizes of what stage of growth the models are in.
Judy set up the augmented reality environment.
Judy: This was my first time working in Unity, and figuring out how to get the augmented reality working with Vuforia was really hectic especially since I already had no idea what was going on. It took a lot of Googling to figure out why my program wasn't running (in the end, it's because Vuforia only works with the 32bit version of Unity, and also webcam only works if you run it in the PC standalone module, not the default Web Player).
In addition, setting up the trigger images also took a bit of testing. For example, with the black "KPDC" logo I originally tested it out on as shown above, for some reason the program wasn't sensing the image. This is because it's rated 1/5 stars in Vuforia, which means the trigger image isn't strong enough.
For testing, I used this 5/5 star trigger image (the kaleidoscope of colors), which worked quite well. Watch the video below which shows its effectiveness with multiple target images as well!
In the end, although we actually got the augmented reality working, we decided against putting it in our final installation.
This is because of our technical and setting limitations. In order for augmented reality to work, it needs good lighting and the target image needs to be relatively close to the webcam in order for it to sense properly, as well as in good focus. We have a really wide workspace in our setup, with four plots, and because we're projecting the images down, they're not as clear as it would need to be for the webcam to sense them efficiently, since they're in a dark environment as well as fuzzy. Also, it's really risky to do augmented reality using projections as target images, because for example, if someone's hand gets in the way of the projection, then the target image would be lost and the augmented reality would disappear, which is way too inconsistent to be polished.
Regardless, it was really exciting getting this part working and perhaps if we had better equipment, this could come into play! (Although in retrospect, I'm not sure if this part actually fits in with our farming theme...and the game itself is so hectic that no one has time to look up and enjoy the augmented reality, though it'd probably draw a lot of eyes from the crowd)
We originally intended for these plot images to also be trigger images, so they have a double function--both for the user interface visuals as well as the augmented reality image targets. As our crops change throughout the game, we need to supply the webcam with new images of the up-to-date status of each plot. As our tabletop trigger zone doubles as a user interface. it's important that these images are meaningful to the user with minimal text.
Images are drawn by Aliya!
We went through a couple iterations of these images as shown below. The biggest issue was that each plot had to be distinctive in order for the augmented reality to register it (although that didn't matter in the end since we decided not to use augmented reality).
The images started off with an icon style, with a circle framing the typical shape of the plant in the forms of seed , young plant, and fully grown plant. It was intended for a brown overlay to indicate a dead plant and a water drop background to indicate the need for water. However the plants for these designs were not the official choices and many aspects of the images were too similar to each other.
The official plant choices were made in Adobe Illustrator and made with circular frames that had different colors to define state. The shapes of these frames were hard for the camera to to define when rotated, so the designs had to be scrapped.
Aliya chose to use different shapes for each plant. By using ovals for one type, she hoped that the rotation would not have as much trouble with the system. However after testing them in the vuforia system, she found that the images were not good trigger designs and had to figure out a quick solution so that tests could be run with the programming.
After reading through an advisory page for trigger image design on vuforia, Aliya found that the vuforia system did not look at the different colors of a trigger image, but the points where two lines met. The more individual points, the more identifiable the image. She placed the trial 3 images over different dirt backgrounds. Planting was given a moist soil background, Watering was given a rocky soil background, and Dead was given a cracked earth background. These triggers worked out well for the system.
The entire Makey Makey circuitry takes quite a bit of time to set up, so we arrived at the installation site really early in the morning to get started. (Aliya was unable to make it on the installation date).
There were a lot of difficulties that we were able to ultimately surpass! For example, we had to ceiling mount the projector in order for it to shine directly down at the tables, but we were worried about getting to the ceiling. Instead, Nathan and Judy figured out an ingenious way to "ceiling mount" by attaching the projector to the vents using zip-ties. Don't worry, the projector is Nathan's, and there was no harm done! In fact it was actually quite effective.
Meanwhile Judy set up the circuitry. For Makey Makey's to work, it needs to create a circuit. We had the users stand on an aluminum foil mat (rigged with wires) with bare feet and by touching the small aluminum squares also connected with a wire, they'd create a circuit with the Makey Makey through their bodies. There are around 22 circuits total, so this took a bit of time.
Originally we wanted to cover the tabletop with a thin white bedsheet so that the projection would shine right over the capacitive surfaces clearly, but the bedsheet was still too thick for the current to go through. But without the bedsheet, the reflective aluminum foil made it really hard to see what was underneath it. In a quick last minute change, we covered the aluminum with tissue paper (though fragile, surprisingly effective), and it made it much more legible.
Throughout the installation demo, we had many testers--sometimes the game got so intense that people would actually rip the tissue paper, but we made quick maintenance checks every once in a while.
It seemed like people had fun :)
Throughout the showcase, Nathan noticed how people interacted with the game and accordingly tweaked the numbers in his code (such as the amount of time it took to harvest, etc) to make the game more challenging and exciting.
I'm pleasantly surprised at the results of this project. What I found was particularly interesting was how much playful human interaction impacted the experience of the game. Whereas some people found their inner competitiveness, others sought more to help their neighbors, but either way it was clear that playing the game together was a key factor in the experience. I'm really proud of how the entire project came together--such as the appealing visuals and the novelty of the hands-on activity with the Makey Makeys.
In retrospect, although I'm disappointed we didn't get to show the augmented reality in action, I think this was a good decision because that part is essentially a different project and isn't the main focus of our game, but I'm still curious to see what the audience's reaction would be. Instead, we decided to put more focus into perfecting the game and making it more polished and beautiful. I really enjoyed working with augmented reality, but also the set up of the whole circuitry of the Makey Makeys was really exciting and thought provoking as we designed the system. Similarly, coming up with game decisions was interesting, as we tried to balance the game to ensure that the game was fast-paced and challenging to promote interaction/difficulty, but still playful and innovative. I learned a lot about augmented reality, which I got really interested in, and I finally got the push to start learning Unity. I'm really happy with our results and I'm glad that people enjoyed playing coFarm with us too!
It seemed that everyone really enjoyed the final project! I loved watching people play during the showcase and watch how different strategies yielded wildly different results. For example, those who took incredibly cooperative strategies often spent as much time ensuring that others didn't have resources as they did watching their own farm, leading to a game with both lower individual and group scores. Players that tended to watch out for each other tended to do better individually and contribute to a higher score. It was also interesting to node that collaboration and cooperation didn't seem to exist within the same playthrough. If one individual was particularly competitive, it seemed that the others followed suit.
It was great to balance the game and see a final working project with very well-implemented components. While I believe that it would have been better with the augmented reality setup we spent so much time working on, I wonder if that would be just a distraction from the core of the game itself for the sake of technology or whether it would have enhanced the game experience in any way. Either way, I'm incredibly happy with how it turned out, and I think that it is a fair representation of both the incredibly hard and long hours we put into the project and the varied talents within our group.
I was pleased to hear that the project went well. Through watching the videos and seeing photos, I was able to get a sense of the enjoyment that my classmates and guests were able to have with the world we created. I do wish we would have been able to implement the augmented reality, but there were too many challenges that would have brought down the presentation. There were a lot of trials with figuring out the system, making the triggers compatible, and getting everything to work together in one piece, but I believe that it was a fun and interesting experience for everyone.
We used IDeATe's Slack to communicate and keep track of official decisions and any important resources.
Programs Used:
HTML, CSS, Javascript- website
Unity and Vuforia- for augmented reality (unused in final product)
Adobe Illustrator & Paint Tool SAI- for drawings
References/Resources:
http://www.justapixel.co.uk/how-to-make-an-ar-app-in-5-minutes-with-unity-and-vuforia/
https://www.youtube.com/watch?v=xh2Ev4kukA0
https://www.youtube.com/watch?v=lU6i2a2143U
https://xfrog.com/category/samples.html
A collaborative farming game that brings out the best and worst of its players.