Talking about GuessNext game, Actionscript 2, Flash, Game development and Monetize.
Time to publish the complete tutorial about the making of GuessNext, a simple card game with highscores.
In order to make an highscore, you must register to Kongregate but you can play even if you don’t register.
It’s not meant to be a good or enjoyable game, it’s simply a programming exercise, so don’t expect the best game ever played before.
Anyway, it’s a good start for developing a complete and interesting card game.
The aim of the game is very simple: from a deck of 52 cards, you have to guess if each card is higher or lower than the previous one. That’s it.
Before we start talking about actionscript, a little information about the graphics.
This is the background
It was made with Photoshop selecting two green colors, one lighter than another, and using a clouds filter. Then, I give the result a light noise filter and the green background was done. The cards on the bottom left side are the same used in the game with a semi-transparent Soft Light blending.
The font is the Death Font you can find on dafont.com at this page.
Now, let’s go with the all-in-one-frame actionscript, just 172 lines to make a complete game
stop();
_root.kongregateServices.connect();
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
var card_shadow:DropShadowFilter = new DropShadowFilter(4, 45, 0x000000, .5, 4, 4, 1, 3, false, false, false);
var text_glow:GlowFilter = new GlowFilter(0x000000, .6, 4, 4, 2, 3, false, false);
show_splash();
function show_splash() {
_root.attachMovie("splash","splash",_root.getNextHighestDepth());
splash.blog_button.onRelease = function() {
getURL("http://emanueleferonato.com/", "_blank");
};
splash.play_button.onRelease = function() {
play_the_game();
splash.removeMovieClip();
};
splash.how_to_button.onRelease = function() {
show_info();
splash.removeMovieClip();
};
}
function show_info() {
_root.attachMovie("info","info",_root.getNextHighestDepth());
info.play_button.onRelease = function() {
play_the_game();
info.removeMovieClip();
};
info.back_button.onRelease = function() {
show_splash();
info.removeMovieClip();
};
}
function play_the_game() {
big_picture = BitmapData.loadBitmap("cardz");
_root.attachMovie("table","table",_root.getNextHighestDepth());
_root.createEmptyMovieClip("game",_root.getNextHighestDepth());
game.attachMovie("higher","higher",game.getNextHighestDepth());
game.attachMovie("lower","lower",game.getNextHighestDepth());
game.createEmptyMovieClip("big_pic_obj",game.getNextHighestDepth());
big_pic_obj.attachBitmap(big_picture,game.getNextHighestDepth());
big_pic_obj._visible = false;
sequence = new Array();
Array.prototype.shuffle = function() {
for (x=0; x<52; x++) {
var from = Math.floor(Math.random()*52);
var to = this[x];
this[x] = this[from];
this[from] = to;
}
};
for (x=0; x<52; x++) {
card = game.createEmptyMovieClip("small_pic_obj_"+x, game.getNextHighestDepth());
sequence[x] = x;
small_picture = new BitmapData(79, 123);
card.attachBitmap(small_picture,game.getNextHighestDepth());
small_picture.copyPixels(big_picture,new Rectangle(0+(x%13)*79, 0+Math.floor(x/13)*123, 79, 123),new Point(0, 0));
card._visible = false;
card.filters = new Array(card_shadow);
card.onEnterFrame = function() {
switch (this.action) {
case "come" :
this._x += 40;
if (this._x>210) {
this._x = 210;
this.action = "stay";
if (cards_drawn>1) {
game.ok_ko._visible = true;
}
}
break;
case "move" :
this._x += 20;
if (this._x>310) {
this._x = 310;
this.action = "dissolve";
}
break;
case "dissolve" :
this._alpha -= 4;
game.lap_score._alpha -= 4;
if (this._alpha<0) {
can_draw = true;
game.ok_ko._visible = false;
if (cards_drawn == 52) {
endgame();
}
this.removeMovieClip();
}
break;
}
};
}
game.attachMovie("ok_ko","ok_ko",game.getNextHighestDepth(),{_x:250, _y:230, _visible:false});
game.attachMovie("score","score",game.getNextHighestDepth(),{_x:0, _y:140});
game.attachMovie("lap_score","lap_score",game.getNextHighestDepth(),{_x:-50, _y:0, _alpha:0});
game.score.filters = new Array(text_glow);
game.lap_score.filters = new Array(text_glow);
sequence.shuffle();
cards_drawn = 0;
points = 0;
can_draw = true;
draw_card();
game.higher.onRelease = function() {
if (can_draw) {
can_draw = false;
higher = true;
draw_card();
}
};
game.lower.onRelease = function() {
if (can_draw) {
can_draw = false;
higher = false;
draw_card();
}
};
}
function draw_card() {
game.ok_ko.gotoAndStop(2);
lap = 0;
if (((sequence[cards_drawn]%13)<=(sequence[cards_drawn-1]%13) and (!higher)) or ((sequence[cards_drawn]%13)>=(sequence[cards_drawn-1]%13) and (higher))) {
game.ok_ko.gotoAndStop(1);
game.lap_score.lap_text.textColor = 0x40ff40;
if (cards_drawn>0) {
if (!higher) {
lap = 13-(sequence[cards_drawn-1]%13);
}
else {
lap = sequence[cards_drawn-1]%13+1;
}
}
}
else {
lap = -5;
game.lap_score.lap_text.textColor = 0x900000;
}
game.lap_score.lap_text.text = lap;
if (cards_drawn>0) {
game.lap_score._alpha = 100;
}
points += lap;
game["small_pic_obj_"+sequence[cards_drawn]]._x = 0;
game["small_pic_obj_"+sequence[cards_drawn]]._y = 10;
game["small_pic_obj_"+sequence[cards_drawn]]._visible = true;
game["small_pic_obj_"+sequence[cards_drawn]].action = "come";
game["small_pic_obj_"+sequence[cards_drawn-1]].action = "move";
cards_drawn++;
game.score.textscore.text = "Cards left: "+(52-cards_drawn)+" - Score: "+points;
}
function endgame() {
game.removeMovieClip();
_root.attachMovie("game_over","game_over",_root.getNextHighestDepth());
game_over.gameovertext.filters = new Array(text_glow);
game_over.fame.filters = new Array(text_glow);
_root.game_over.gameovertext.text = "Your score: "+points;
_root.kongregateScores.submit(points);
game_over.fame.text = "top five players\n";
var scoresCallback:Function = function (result:Object) {
for (var i:Number = 0; i
Line 1: This stop
is necessary bacause the game actually is on the second frame. I had to reserve the first frame to MochiAds and MochiBot just in case some day I would decide to monetize the game.
Line 2: connecting to the Kongregate server
Lines 3-7: importing various Flash prebuilt libraries I will use into the game
Lines 8-9: Defining the filter that I will use for the cards and for the texts. I am using a shadow for the cards, and a glow for the texts. For more information about Flash filters, refer to Create a flash draw game like Line Rider or others - part 1
Line 10: Calling the show_splash
function. This function will show the game splash screen
Line 11: Beginning of the show_splash
function
Line 12: Attaching the splash
movieclip. It's this one
and has three transparent buttons in it: one on the "how to play", one on the "play" and one on the url of my blog
Lines 13-15: Managing the click on the button over the url of my blog, and opening the blog on a new page with getURL
LInes 16-19: Managing the click on the play button, calling the play_the_game
function that contains the game itself, then removing the splash
movieclip
Lines 20-23: Managing the "how to play" button, calling the show_info function that contains the script for the game instructions, the removing the splash
movieclip. This concept of managing game status is similar to the one I explained in the post Designing the structure of a Flash game
Line 25: Beginning of the show_info
function
Line 26: Attaching the info
movieclip. It's this one:
and like the splash
one has transparent buttons on the "play" and "back" texts
Lines 27-30: Managing the play button like in lines 16-19
Lines 31-34: Managing the back button calling again the show_splash
function and removing the info
movieclip
Line 36: Beginning of the play_game
function, the core of the game
Line 37: Loading the card deck with BitmapData. More information about BitmapData in the post Shuffle an image with BitmapData
Lines 38-42: Attaching and creating all movieclips used in the game: the background (table
), a movieclip where to publish all game elements (game
), the buttons to bet on higher or lower cards (higher and lower
) and the one to contain the cards (big_pic_obj
)
Line 43: Attaching the bitmap as explained in the post Shuffle an image with BitmapData
Line 44: Hiding the movieclip with all cards
Line 45: Declaring the array that will store the sequence of cards that will be drawn during the game
Lines 46-53: Defining the prototype to shuffle the cards as explained in the post Shuffle an image with BitmapData
Line 54: Beginning of the loop that will cycle through all 52 cards
Line 55: Creating the empty movieclip that will host the card
Line 56: Assigning x
to the x
-th element in the sequence
array. I need an ordered sequence (of cards) before I shuffle the deck
Line 57-59: Copying the pixels of each card into the appropriate movieclip as explained in the post Shuffle an image with BitmapData
Line 60: Making the card invisible
Line 61: Adding the shadow filter to the card
Line 62: Beginning of the actions to be executed for each card at every frame
Line 63: Switching among some defined actions the card may execute: come
means the card is coming from the left side of the game to the centre of the screen, move
means the card is moving from the centre to the right, and dissolve
is when the card disappears from the game
Line 64: Beginning of the come
case
Line 65: Moving the card to the right by 40 picels
Lines 66-68: If the card x position is greater than 210 (passed the orizontal center of the screen), then set its x position to 210 (place on the horizontal center the screen), set the card action to stay
(that does not exist in the switch
cases, it's something like "do nothing")
Lines 69-71: If the number of cards drawn is greater than 1 (if it's not the first card, the one you start the game with) then make the ok_ko
movieclip visible. The ok_ko movieclip is the movieclip with the green "ok" symbol and the red "wrong" one that will appear when you draw a card. The "ok" is on the first frame while the "wrong" on the second
Line 74: Beginning of the move
case
Line 75: Move the card to the right by 20 pixels
Lines 76-79: If the card x position is greater than 310, set the x position to 310 and set the card action to dissolve
(it's time to make the card disappear)
Line 81: Beginning of the dissolve
case
Line 82: Decrease the alpha of the card by 4 units
Line 83: Decrease the alpha of the lap_score
movieclip by 4 units. The lap_score
movieclip is the score that will appear on the top left side of the game when you draw a card
Line 84: If the card alpha is less than zero (invisible)...
Line 85: Set the can_draw
variable to true. The can_draw
variable states if the player can draw the next card or not. I made this variable because I want the player to wait until the previous card disappears. It has only a design purpose, I don't want the player to click randomly across the screen or click twice for an error
Line 86: Set the ok_ko
movieclip to invisible
Lines 87-89: If the number of cards drawn is 52 (if the entire deck has been drawn), then call the endgame
function
Line 90: Removing the card movieclip
Lines 96-98: Attaching the remaining movieclips being used in the game: ok_ko (the two symbols of right/wrong choice), score (the text with the current score and the cards left) and lap_score (the text with the partial score). This way:
Lines 99-100: Applying the glow filter to score
and lap_score
texts
Line 101: Shuffling the deck (sequence
array)
Line 102: Set the number of cards drawn to zero
Line 103: Setting the points to zero
Line 104: Defining that the player at this time can draw the next card
Line 105: Calling the draw_card
function. This function manages the next card to be drawn
Line 106: Beginning of the actions to be executed when the higher
button has been released (the button with an up arrow)
Lines 107-111: If the player can draw, then set the can_draw
variable to false
(he must wait before drawing another card), set the higher
variable to true
(the variable that holds the choice of the player) and call the draw_card
function
Lines 113-120: Same thing with the lower
button, with the only difference in line 116 where higher
variable is set to false
Line 121: Beginning of the draw_card function
Line 122: Move the ok_ko
movieclip to frame 2
Line 123: Setting the lap score (the score for the current hand) to zero
Line 124: Checking if the player did the right choice. It happens when the player pressed higher and the current card is higher (or equal) than the previous one, or if the player pressed lower and the current card is lower (or equal) than the previous one. The %13
in the code is necessary because every suit (or seed) has 13 cards, so if an ace is the xth
card, I know next ace will be the (x+13)th
one. As you can see, if two cards are equals, the bet is always won, no matter the seeds of the cards.
Line 125: Moving the ok_ko
movieclip to frame 1 (the "ok" symbol)
Line 126: Setting the text color of the lap score to a light green
Line 127: Determining if it's not the first card drawn (the one you see when you start the game)
Lines 128-133: Determining the partial score. The game encourages bets again statistics so if you have a ten, you know you have four cards higher (10, J, Q, K) and nine lower (from 1 to 10). So the game will give nine points if you bet (and win) on higher, and four if your bet (and win) to lower
Line 136: Beginning of the code to be executed if you did not bet and win
Line 137: Setting the lap score to -5. If you don't win, you always lose 5 points
Line 138: Setting the text color of the lap score to a dark red
Line 140: Writing the score of the last bet in the lap score text
Lines 141-143: Showing the lap score if the card drawn is not the first one (the one you see when you start the game)
Line 144: Adding the lap score to the total score
Lines 145-149: Assigning properties and actions to the cards involved in the last bet: the last one is placed to (0, 10), made visible and with the come
action while the last one is set to move
action
Line 150: Increasing the number of cards drawn
Line 151: Updating the score text with the total score and the number of cards left
Line 153: Beginning of the endgame
function to be executed when the game ends
Line 154: Removing the game
movieclip (with all cards, buttons, scores, and so on)
Line 155: Attaching the game_over
movieclip. It's a movieclip showing your score and the top 5 players
Lines 156-157: Applying the glow array to the gameovertext
(the text with your final score) and fame
(the text with the top five scores) texts
Line 158: Displaying your final score
Line 159: Submitting the score to Kongregate. You are submitting only the score, without your name, because highscores work only if you are a registered user. In that case, the name is the nickname you use in Kongregate.
Lines 160-167: Code to retrieve the top five players. It's the standard code you may find on this page, I just changed line 164 to display the scores in my fame
text and remove the trace
lines. Notice that I am writing all scores and not just the top five, but the fame
text will show only the top five.
Lines 168-172: Managing the play button you can find in the game over screen: it's the same concept as seen in lines 16-19
And that's it!! Hope this will inspire you in a card game creation.
Download the source code and all the Photoshop files and give me feedback!
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.