Appendix IV
COVER PAGE & TITLE PAGE
Solitaire
Report submitted in partial fulfillment of the requirements for the
award of the Degree of
BACHELOR OF COMPUTER APPLICATION
of
CMR UNIVERSITY
By
Anirudh Muralidhar
Reg. No. 17BCAG009
Under the guidance of
Ramesh Kumar K
Head of Associates 2017-2019
CMR University
CMR UNIVERSITY
2017-20
Appendix V
DECLARATION (BY THE STUDENT)
I hereby declare that the internship work entitled “Solitaire” submitted to the School of Social Sciences
& Humanities, CMR University, Bangalore, is a record of an original work done by me under the guidance
of Ramesh Kumar K, Head of Associates, BCA Department, CMR University and this internship report is
submitted in the partial fulfilment of the requirements of fourth semester Examinations.
I also declare that this project is the outcome of my own efforts and that it has not been submitted to any
other university or Institute for the award of any other degree or Diploma or Certificate.
Place: Name: Anirudh Muralidhar
Date: Register Number: 17BCAG009
2
CONTENTS
Sl No Name PageNo
1 Game Overview 4
1.1 Game Concept 4
1.2 Genre 4
1.3 Target Platform 4
1.4 Game Flow Concept 4
2 Game Play 5
2.1 Game Progression 5
2.2 Objectives 5
2.3 Game Structure 5
2.4 Play Flow 5
3 Game Mechanics 6
3.1 Card Generation 6
3.2 Card Distribution 6
3.3 Card Slot 6
3.4 Card Script 6
3.5 Game UI Script 18
3.6 Menu Script 18
4 Screenshots 19
3
GAME OVERVIEW
Game Concept
The game is the classical card game solitaire. The game is played with a
single pack of 52 playing cards. After thoroughly shuffling the deck, 28
cards are dealt face down to form the tableau which consists of 7 columns of
1,2,3,4,5,6 and 7 overlapping cards from left to right respectively. The
exposed card at the end of each tableau column is turned face up. The goal
is to get all the cards sorted into the suit slots where the cards have to be
arranged in ascending order starting from ace.
Genre
Card Game
Target Platform
Android and PC
Target Audience
casual gamers and Card game lovers of ages 12+
Game Flow Summary
The game is re-playable as each time the game starts the cards are reshuffled
and rearranged in the format described above with the same objective. The
player competes against himself to get the fastest time and improve his win
percentage.
Development Software
Unity 3D
4
GAMEPLAY
Game Progression
The game is a where cards are shuffled and then placed to form the tableau
which consists of 7 columns of 1,2,3,4,5,6 and 7 overlapping cards from left
to right respectively. The card at the front of each column will be turned
face up and the rest will be turned face down. The rest of the cards are
placed in the draw pile where the player can click and can cycle through all
the cards that are part of the draw pile. When a card is removed from the
dray pile the card before it is in view again
Objectives
The goal is to get all the cards sorted into the suite slots where the cards
have to be arranged in ascending order starting from ace. Each suite has its
own slot it has to go into.
Game Structure
Cards can be attached to one another in such a way that a red card can only
sit on a black card of the number of just one higher than itself i.e. a 6 of
hearts can only be placed on either a 7 of spades, a seven of clubs or on the
5 of spades that is already in the spade suite slot. Cards that are initially face
down in the play area can only be turned over if the card in front of them is
removed and put in a suitable place.
Play Flow
The game is highly replay able as the beyond 10 ^ 60 so the chance of the
same game playing out in front of the player is beyond miniscule. The
player gets satisfaction from beating his own high score and improving his
win percentage
5
Game Mechanics
Card Generation
The cards are created using a prefab and a nested for loop at the start of the
game. The inner for loop changes the value of the cars i.e. 2,3,4… and the
outer for loop changes the suite i.e. spades, clubs…… the cards are assigned
into an array where all the cards are stored initially. Then using a for loop
random elements within the array are swapped with each other such that the
position of the cards are changed and the deck is shuffled this swapping is
done 500 times to keep the game different each time.
Card Distribution
The cards are then distributed in the way described in the Structure using a
nested for loop where the inner one decides how many cards to put in the
column and the outer one changes between the columns.
Card Slot
The card slot contains all the cards that are not in the play area at the start of
the game and when we click on the card slot it cycles through all the cards
in a linear order if a card is removed we can see the card below it cards can
be moved from the card slot to the play area or suite slot if a suitable
position is open for them else if they are dragged out and not placed in a
suitable position the card resets back into the card slot.
Card Script
The Card script contains the logic to detect whether a card has to be flipped
or not. When a face up card is click on its collider is disabled and its
position is set to the mouse or touches position and when the finger or
mouse is released, it also checks the logic for detecting if the card has been
placed in a legal place if it is not the cards position is reset. To its original
position in both cases the collider is re-enabled. This is the most important
script in the game and is shown below
using UnityEngine;
using System.Collections;
6
public class CardScript : MonoBehaviour {
Collider col;
bool clicked;
public string shapetype;
public string[] cardvals;
public int valindex;
public int slotindex;
bool changepos;
Ray ray;
RaycastHit hit;
Vector3 hitpoint;
Vector3 initialpos;
Vector2 offset;
Ray ray1;
RaycastHit hit1;
public bool cardflipped;
public static bool heartscompleted;
public static bool clubscompleted;
public static bool diamondscompleted;
public static bool spadescompleted;
// Use this for initialization
void Start ()
{
col = this.GetComponent<BoxCollider> ();
}
// Update is called once per frame
void Update()
{
changepos = false;
if (this.valindex == 12)
{
7
if (this.shapetype == "Club")
{
if (this.slotindex == 2)
{
clubscompleted = true;
}
else
clubscompleted = false;
}
if (this.shapetype == "Diamond")
{
if (this.slotindex == 3)
{
diamondscompleted = true;
}
else
diamondscompleted = false;
}
if (this.shapetype == "Heart")
{
if (this.slotindex == 4)
{
heartscompleted = true;
}
else
heartscompleted = false;
}
if (this.shapetype == "Spade")
{
if (this.slotindex == 5)
{
spadescompleted = true;
}
else
spadescompleted = false;
}
}
8
if (cardflipped)
{
if (this.transform.eulerAngles.y != 180)
{
this.transform.eulerAngles = new Vector3(0, 180, 0);
}
}
else
{
if (this.transform.eulerAngles.y != 0)
{
this.transform.eulerAngles = new Vector3(0, 0, 0);
}
}
if (clicked)
{
MoveCard();
if (Input.GetMouseButtonUp(0))
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
if (this.GetComponent<CardScript>().valindex != 12)
{
if (hit.collider.tag == "card")
{
if (hit.collider.GetComponent<CardScript>().cardflipped)
{
if (hit.collider.GetComponent<CardScript>().slotindex
== 1)
{
if ((this.GetComponent<CardScript>().shapetype ==
"Spade") || (this.GetComponent<CardScript>().shapetype == "Club"))
{
9
if
((hit.collider.GetComponent<CardScript>().shapetype == "Diamond") ||
(hit.collider.GetComponent<CardScript>().shapetype == "Heart"))
{
if (this.GetComponent<CardScript>().valindex
== hit.collider.GetComponent<CardScript>().valindex - 1)
{
this.transform.position =
hit.transform.GetChild(3).transform.position;
this.transform.SetParent(hit.transform);
this.changepos = true;
this.slotindex = 1;
}
}
}
else if ((this.GetComponent<CardScript>().shapetype
== "Heart") || (this.GetComponent<CardScript>().shapetype ==
"Diamond"))
{
if
((hit.collider.GetComponent<CardScript>().shapetype == "Spade") ||
(hit.collider.GetComponent<CardScript>().shapetype == "Club"))
{
if (this.GetComponent<CardScript>().valindex
== hit.collider.GetComponent<CardScript>().valindex - 1)
{
this.transform.position =
hit.transform.GetChild(3).transform.position;
this.transform.SetParent(hit.transform);
this.changepos = true;
this.slotindex = 1;
}
}
}
}
10
else if
((hit.collider.GetComponent<CardScript>().slotindex ==
2)&&(this.transform.childCount<=4))
{
if (this.shapetype == "Club")
{
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 2;
this.transform.SetParent(null);
}
}
}
}
else if
((hit.collider.GetComponent<CardScript>().slotindex == 3) &&
(this.transform.childCount <= 4))
{
if (this.shapetype == "Diamond")
{
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 3;
11
this.transform.SetParent(null);
}
}
}
}
else if
((hit.collider.GetComponent<CardScript>().slotindex == 4) &&
(this.transform.childCount <= 4))
{
if (this.shapetype == "Heart")
{
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 4;
this.transform.SetParent(null);
}
}
}
}
if ((hit.collider.GetComponent<CardScript>().slotindex
== 5) && (this.transform.childCount <= 4))
{
if (this.shapetype == "Spade")
{
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
12
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 5;
this.transform.SetParent(null);
}
}
}
}
}
}
else if (hit.collider.name == "ClubSlot")
{
if ((this.valindex == 0) && (this.shapetype == "Club"))
{
this.transform.position = hit.transform.position;
this.changepos = true;
this.slotindex = 2;
this.transform.SetParent(null);
}
}
else if (hit.collider.name == "DiamondSlot")
{
if ((this.valindex == 0) && (this.shapetype ==
"Diamond"))
{
this.transform.position = hit.transform.position;
this.changepos = true;
this.slotindex = 3;
this.transform.SetParent(null);
}
}
else if (hit.collider.name == "HeartSlot")
{
if ((this.valindex == 0) && (this.shapetype == "Heart"))
{
13
this.transform.position = hit.transform.position;
this.changepos = true;
this.slotindex = 4;
this.transform.SetParent(null);
}
}
else if (hit.collider.name == "SpadeSlot")
{
if ((this.valindex == 0) && (this.shapetype == "Spade"))
{
this.transform.position = hit.transform.position;
this.changepos = true;
this.slotindex = 5;
this.transform.SetParent(null);
}
}
}
else if ((this.GetComponent<CardScript>().valindex == 12) &&
(hit.collider != null))
{
if (hit.collider.tag == "GameSlot")
{
this.transform.position = hit.transform.position;
this.changepos = true;
this.slotindex = 1;
this.transform.SetParent(null);
}
else if (hit.collider.tag == "card")
{
if ((hit.collider.GetComponent<CardScript>().slotindex ==
2) && (this.transform.childCount <= 4))
{
if (this.shapetype == "Club")
{
if (hit.collider.GetComponent<CardScript>().valindex
== this.valindex - 1)
{
14
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 2;
this.transform.SetParent(null);
}
}
}
else if
((hit.collider.GetComponent<CardScript>().slotindex == 3) &&
(this.transform.childCount <= 4))
{
if (this.shapetype == "Diamond")
{
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 3;
this.transform.SetParent(null);
}
}
}
}
else if
((hit.collider.GetComponent<CardScript>().slotindex == 4) &&
(this.transform.childCount <= 4))
{
if (this.shapetype == "Heart")
{
15
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 4;
this.transform.SetParent(null);
}
}
}
}
else if
((hit.collider.GetComponent<CardScript>().slotindex == 5) &&
(this.transform.childCount <= 4))
{
if (this.shapetype == "Spade")
{
if (this.valindex != 0)
{
if
(hit.collider.GetComponent<CardScript>().valindex == this.valindex - 1)
{
this.transform.position = new
Vector3(hit.transform.position.x, hit.transform.position.y,
hit.transform.position.z - 0.2f);
this.changepos = true;
this.slotindex = 5;
this.transform.SetParent(null);
}
}
}
}
}
16
}
clicked = false;
col.enabled = true;
if (!changepos)
this.transform.position = initialpos;
}
}
}
if (this.slotindex == 1)
{
if (this.transform.Find("Card_Close(Clone)") == null)
this.cardflipped = true;
}
}
void MoveCard()
{
ray1 = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray1, out hit1))
{
hitpoint.x = hit1.point.x + offset.x;
hitpoint.y = hit1.point.y + offset.y;
hitpoint.z = -3;
this.transform.position = hitpoint;
}
}
void OnMouseDown()
{
if ((!clicked)&&(cardflipped))
{
17
ray = Camera.main.ScreenPointToRay
(Input.mousePosition);
if (Physics.Raycast (ray, out hit))
{
offset.x = this.transform.position.x - hit.point.x;
offset.y = this.transform.position.y - hit.point.y;
}
clicked = true;
col.enabled = false;
initialpos = transform.position;
}
}
}
Game UI Script
This script contains the functionality of the buttons in the game scene. It
also contains the timer script as well as checking the win condition and
spawning the winners screen as well as the data for fastest time and number
of wins and their updating.
Menu Script
This script contains the functionality of the buttons on the main menu.
18
Screenshots from The Game
Main Menu
Credits Panel
19
Game Screen
Pause Screen
20
Win Screen
21