/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var ColorChooser = Container.expand(function () { var self = Container.call(this); self.visible = false; var colors = ['red', 'blue', 'green', 'yellow']; var colorValues = [0xFF4444, 0x4444FF, 0x44FF44, 0xFFFF44]; for (var i = 0; i < 4; i++) { var colorBtn = self.attachAsset('colorButton', { anchorX: 0.5, anchorY: 0.5, x: i % 2 * 140 - 70, y: Math.floor(i / 2) * 140 - 70, tint: colorValues[i] }); colorBtn.colorName = colors[i]; colorBtn.down = function (x, y, obj) { chooseWildColor(obj.colorName); }; } return self; }); var UnoCard = Container.expand(function (color, value) { var self = Container.call(this); self.color = color; // 'red', 'blue', 'green', 'yellow', 'wild' self.value = value; // 0-9, 'skip', 'reverse', 'draw2', 'wild', 'wilddraw4' self.isPlayable = false; // Create card background var cardAssetId = color + 'Card'; if (color === 'wild') cardAssetId = 'wildCard'; var cardBg = self.attachAsset(cardAssetId, { anchorX: 0.5, anchorY: 0.5 }); // Add card text var cardText = new Text2(self.value.toString(), { size: 24, fill: color === 'yellow' ? "#000000" : "#FFFFFF" }); cardText.anchor.set(0.5, 0.5); self.addChild(cardText); self.setPlayable = function (playable) { self.isPlayable = playable; cardBg.alpha = playable ? 1.0 : 0.6; }; self.canPlayOn = function (topCard) { if (self.color === 'wild') return true; if (self.color === topCard.color) return true; if (self.value === topCard.value && typeof self.value === 'number') return true; return false; }; self.down = function (x, y, obj) { if (self.isPlayable && currentPlayer === 0) { playCard(self); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x006600 }); /**** * Game Code ****/ // Sound effects // UNO Card assets // Game state variables var player1Hand = []; var player2Hand = []; var discardPile = []; var drawPile = []; var currentPlayer = 0; // 0 = player 1, 1 = player 2 var gameDirection = 1; // 1 = forward, -1 = reverse var pendingWildCard = null; var player1Score = 0; var player2Score = 0; var targetScore = 500; // UI elements var scoreText = new Text2('Player 1: 0 Player 2: 0', { size: 40, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var currentPlayerText = new Text2('Player 1 Turn', { size: 36, fill: 0xFFFF00 }); currentPlayerText.anchor.set(0.5, 0); currentPlayerText.y = 60; LK.gui.top.addChild(currentPlayerText); var unoButton = game.attachAsset('unoButton', { anchorX: 0.5, anchorY: 0.5, x: 1700, y: 2200 }); var unoButtonText = new Text2('UNO!', { size: 32, fill: 0xFFFFFF }); unoButtonText.anchor.set(0.5, 0.5); unoButton.addChild(unoButtonText); var colorChooser = game.addChild(new ColorChooser()); colorChooser.x = 1024; colorChooser.y = 1366; // Discard pile area var discardArea = game.attachAsset('discardPile', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); // Initialize deck function createDeck() { var deck = []; var colors = ['red', 'blue', 'green', 'yellow']; // Number cards (0-9) for (var c = 0; c < colors.length; c++) { var color = colors[c]; // One 0 card per color deck.push({ color: color, value: 0 }); // Two of each 1-9 card per color for (var v = 1; v <= 9; v++) { deck.push({ color: color, value: v }); deck.push({ color: color, value: v }); } // Action cards (2 of each per color) deck.push({ color: color, value: 'skip' }); deck.push({ color: color, value: 'skip' }); deck.push({ color: color, value: 'reverse' }); deck.push({ color: color, value: 'reverse' }); deck.push({ color: color, value: 'draw2' }); deck.push({ color: color, value: 'draw2' }); } // Wild cards (4 of each) for (var w = 0; w < 4; w++) { deck.push({ color: 'wild', value: 'wild' }); deck.push({ color: 'wild', value: 'wilddraw4' }); } return deck; } function shuffleDeck(deck) { for (var i = deck.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } } function dealCards() { // Create and shuffle deck var deck = createDeck(); shuffleDeck(deck); // Deal 7 cards to each player for (var i = 0; i < 7; i++) { var card1 = new UnoCard(deck[i].color, deck[i].value); var card2 = new UnoCard(deck[i + 7].color, deck[i + 7].value); // Set initial positions for the cards before adding to game card1.x = 1024; card1.y = 1366; card2.x = 1024; card2.y = 1366; player1Hand.push(card1); player2Hand.push(card2); game.addChild(card1); game.addChild(card2); } // Set up draw pile for (var d = 14; d < deck.length - 1; d++) { drawPile.push(deck[d]); } // Start discard pile var startCard = deck[deck.length - 1]; var topCard = new UnoCard(startCard.color, startCard.value); discardPile.push(topCard); game.addChild(topCard); arrangeCards(); } function arrangeCards() { // Arrange player 1 hand (bottom) var cardSpacing = 120; // Increased spacing var startX = 1024 - player1Hand.length * cardSpacing / 2; for (var i = 0; i < player1Hand.length; i++) { var card = player1Hand[i]; card.x = startX + i * cardSpacing; card.y = 2500; card.rotation = 0; } // Arrange player 2 hand (top, face down) var cardSpacing = 120; // Increased spacing var startX2 = 1024 - player2Hand.length * cardSpacing / 2; for (var j = 0; j < player2Hand.length; j++) { var card2 = player2Hand[j]; card2.x = startX2 + j * cardSpacing; card2.y = 200; card2.rotation = Math.PI; } // Position top discard card if (discardPile.length > 0) { var topCard = discardPile[discardPile.length - 1]; topCard.x = 1024; topCard.y = 1366; } updatePlayableCards(); } function updatePlayableCards() { if (discardPile.length === 0) return; var topCard = discardPile[discardPile.length - 1]; // Update player 1 cards for (var i = 0; i < player1Hand.length; i++) { var canPlay = player1Hand[i].canPlayOn(topCard); player1Hand[i].setPlayable(canPlay); } } function playCard(card) { if (currentPlayer !== 0) return; var cardIndex = player1Hand.indexOf(card); if (cardIndex === -1) return; // Remove card from hand player1Hand.splice(cardIndex, 1); // Add to discard pile discardPile.push(card); // Position card on discard pile card.x = 1024; card.y = 1366; LK.getSound('cardPlay').play(); // Handle special cards if (card.color === 'wild') { pendingWildCard = card; colorChooser.visible = true; return; } executeCardEffect(card); // Check for UNO if (player1Hand.length === 1) { // Player should call UNO LK.setTimeout(function () { if (player1Hand.length === 1) { // Penalty for not calling UNO drawCards(0, 2); LK.getSound('penalty').play(); } }, 3000); } // Check for win if (player1Hand.length === 0) { endRound(0); return; } arrangeCards(); nextTurn(); } function executeCardEffect(card) { switch (card.value) { case 'skip': // Skip next player nextTurn(); break; case 'reverse': gameDirection *= -1; break; case 'draw2': drawCards(1, 2); nextTurn(); break; case 'wilddraw4': drawCards(1, 4); nextTurn(); break; } } function chooseWildColor(color) { if (!pendingWildCard) return; pendingWildCard.color = color; colorChooser.visible = false; executeCardEffect(pendingWildCard); pendingWildCard = null; arrangeCards(); nextTurn(); } function drawCards(player, count) { for (var i = 0; i < count; i++) { if (drawPile.length === 0) { reshuffleDiscardPile(); } if (drawPile.length > 0) { var cardData = drawPile.pop(); var newCard = new UnoCard(cardData.color, cardData.value); game.addChild(newCard); if (player === 0) { player1Hand.push(newCard); } else { player2Hand.push(newCard); } } } LK.getSound('cardDraw').play(); arrangeCards(); } function reshuffleDiscardPile() { if (discardPile.length <= 1) return; // Keep top card, shuffle rest back into draw pile var topCard = discardPile.pop(); while (discardPile.length > 0) { var card = discardPile.shift(); drawPile.push({ color: card.color, value: card.value }); card.destroy(); } discardPile.push(topCard); shuffleDeck(drawPile); } function nextTurn() { currentPlayer = (currentPlayer + gameDirection + 2) % 2; if (currentPlayer === 0) { currentPlayerText.setText('Player 1 Turn'); } else { currentPlayerText.setText('Player 2 Turn'); // AI turn LK.setTimeout(function () { playAITurn(); }, 1000); } updatePlayableCards(); } function playAITurn() { if (currentPlayer !== 1) return; var topCard = discardPile[discardPile.length - 1]; var playableCards = []; // Find playable cards for (var i = 0; i < player2Hand.length; i++) { if (player2Hand[i].canPlayOn(topCard)) { playableCards.push(i); } } if (playableCards.length > 0) { // Play a random playable card var randomIndex = playableCards[Math.floor(Math.random() * playableCards.length)]; var card = player2Hand[randomIndex]; // Remove from hand player2Hand.splice(randomIndex, 1); // Add to discard pile discardPile.push(card); card.x = 1024; card.y = 1366; card.rotation = 0; LK.getSound('cardPlay').play(); // Handle wild cards if (card.color === 'wild') { var colors = ['red', 'blue', 'green', 'yellow']; card.color = colors[Math.floor(Math.random() * 4)]; } executeCardEffect(card); // Check for win if (player2Hand.length === 0) { endRound(1); return; } arrangeCards(); nextTurn(); } else { // Draw a card drawCards(1, 1); nextTurn(); } } function endRound(winner) { // Calculate points var points = 0; var loserHand = winner === 0 ? player2Hand : player1Hand; for (var i = 0; i < loserHand.length; i++) { var card = loserHand[i]; if (typeof card.value === 'number') { points += card.value; } else if (card.value === 'skip' || card.value === 'reverse' || card.value === 'draw2') { points += 20; } else { points += 50; // Wild cards } } if (winner === 0) { player1Score += points; } else { player2Score += points; } scoreText.setText('Player 1: ' + player1Score + ' Player 2: ' + player2Score); // Check for game win if (player1Score >= targetScore) { LK.showYouWin(); } else if (player2Score >= targetScore) { LK.showGameOver(); } else { // Start new round LK.setTimeout(function () { startNewRound(); }, 2000); } } function startNewRound() { // Clear hands and discard pile for (var i = 0; i < player1Hand.length; i++) { player1Hand[i].destroy(); } for (var j = 0; j < player2Hand.length; j++) { player2Hand[j].destroy(); } for (var k = 0; k < discardPile.length; k++) { discardPile[k].destroy(); } player1Hand = []; player2Hand = []; discardPile = []; drawPile = []; currentPlayer = 0; gameDirection = 1; pendingWildCard = null; colorChooser.visible = false; dealCards(); } // UNO button handler unoButton.down = function (x, y, obj) { if (player1Hand.length === 1) { LK.getSound('unoCall').play(); } }; // Draw card area (right side of screen) game.down = function (x, y, obj) { if (x > 1500 && x < 2048 && y > 1200 && y < 1600 && currentPlayer === 0) { // Draw card area clicked var topCard = discardPile[discardPile.length - 1]; var hasPlayableCard = false; for (var i = 0; i < player1Hand.length; i++) { if (player1Hand[i].canPlayOn(topCard)) { hasPlayableCard = true; break; } } if (!hasPlayableCard) { drawCards(0, 1); nextTurn(); } } }; // Initialize game dealCards(); currentPlayerText.setText('Player 1 Turn');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ColorChooser = Container.expand(function () {
var self = Container.call(this);
self.visible = false;
var colors = ['red', 'blue', 'green', 'yellow'];
var colorValues = [0xFF4444, 0x4444FF, 0x44FF44, 0xFFFF44];
for (var i = 0; i < 4; i++) {
var colorBtn = self.attachAsset('colorButton', {
anchorX: 0.5,
anchorY: 0.5,
x: i % 2 * 140 - 70,
y: Math.floor(i / 2) * 140 - 70,
tint: colorValues[i]
});
colorBtn.colorName = colors[i];
colorBtn.down = function (x, y, obj) {
chooseWildColor(obj.colorName);
};
}
return self;
});
var UnoCard = Container.expand(function (color, value) {
var self = Container.call(this);
self.color = color; // 'red', 'blue', 'green', 'yellow', 'wild'
self.value = value; // 0-9, 'skip', 'reverse', 'draw2', 'wild', 'wilddraw4'
self.isPlayable = false;
// Create card background
var cardAssetId = color + 'Card';
if (color === 'wild') cardAssetId = 'wildCard';
var cardBg = self.attachAsset(cardAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add card text
var cardText = new Text2(self.value.toString(), {
size: 24,
fill: color === 'yellow' ? "#000000" : "#FFFFFF"
});
cardText.anchor.set(0.5, 0.5);
self.addChild(cardText);
self.setPlayable = function (playable) {
self.isPlayable = playable;
cardBg.alpha = playable ? 1.0 : 0.6;
};
self.canPlayOn = function (topCard) {
if (self.color === 'wild') return true;
if (self.color === topCard.color) return true;
if (self.value === topCard.value && typeof self.value === 'number') return true;
return false;
};
self.down = function (x, y, obj) {
if (self.isPlayable && currentPlayer === 0) {
playCard(self);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x006600
});
/****
* Game Code
****/
// Sound effects
// UNO Card assets
// Game state variables
var player1Hand = [];
var player2Hand = [];
var discardPile = [];
var drawPile = [];
var currentPlayer = 0; // 0 = player 1, 1 = player 2
var gameDirection = 1; // 1 = forward, -1 = reverse
var pendingWildCard = null;
var player1Score = 0;
var player2Score = 0;
var targetScore = 500;
// UI elements
var scoreText = new Text2('Player 1: 0 Player 2: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var currentPlayerText = new Text2('Player 1 Turn', {
size: 36,
fill: 0xFFFF00
});
currentPlayerText.anchor.set(0.5, 0);
currentPlayerText.y = 60;
LK.gui.top.addChild(currentPlayerText);
var unoButton = game.attachAsset('unoButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1700,
y: 2200
});
var unoButtonText = new Text2('UNO!', {
size: 32,
fill: 0xFFFFFF
});
unoButtonText.anchor.set(0.5, 0.5);
unoButton.addChild(unoButtonText);
var colorChooser = game.addChild(new ColorChooser());
colorChooser.x = 1024;
colorChooser.y = 1366;
// Discard pile area
var discardArea = game.attachAsset('discardPile', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
// Initialize deck
function createDeck() {
var deck = [];
var colors = ['red', 'blue', 'green', 'yellow'];
// Number cards (0-9)
for (var c = 0; c < colors.length; c++) {
var color = colors[c];
// One 0 card per color
deck.push({
color: color,
value: 0
});
// Two of each 1-9 card per color
for (var v = 1; v <= 9; v++) {
deck.push({
color: color,
value: v
});
deck.push({
color: color,
value: v
});
}
// Action cards (2 of each per color)
deck.push({
color: color,
value: 'skip'
});
deck.push({
color: color,
value: 'skip'
});
deck.push({
color: color,
value: 'reverse'
});
deck.push({
color: color,
value: 'reverse'
});
deck.push({
color: color,
value: 'draw2'
});
deck.push({
color: color,
value: 'draw2'
});
}
// Wild cards (4 of each)
for (var w = 0; w < 4; w++) {
deck.push({
color: 'wild',
value: 'wild'
});
deck.push({
color: 'wild',
value: 'wilddraw4'
});
}
return deck;
}
function shuffleDeck(deck) {
for (var i = deck.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
function dealCards() {
// Create and shuffle deck
var deck = createDeck();
shuffleDeck(deck);
// Deal 7 cards to each player
for (var i = 0; i < 7; i++) {
var card1 = new UnoCard(deck[i].color, deck[i].value);
var card2 = new UnoCard(deck[i + 7].color, deck[i + 7].value);
// Set initial positions for the cards before adding to game
card1.x = 1024;
card1.y = 1366;
card2.x = 1024;
card2.y = 1366;
player1Hand.push(card1);
player2Hand.push(card2);
game.addChild(card1);
game.addChild(card2);
}
// Set up draw pile
for (var d = 14; d < deck.length - 1; d++) {
drawPile.push(deck[d]);
}
// Start discard pile
var startCard = deck[deck.length - 1];
var topCard = new UnoCard(startCard.color, startCard.value);
discardPile.push(topCard);
game.addChild(topCard);
arrangeCards();
}
function arrangeCards() {
// Arrange player 1 hand (bottom)
var cardSpacing = 120; // Increased spacing
var startX = 1024 - player1Hand.length * cardSpacing / 2;
for (var i = 0; i < player1Hand.length; i++) {
var card = player1Hand[i];
card.x = startX + i * cardSpacing;
card.y = 2500;
card.rotation = 0;
}
// Arrange player 2 hand (top, face down)
var cardSpacing = 120; // Increased spacing
var startX2 = 1024 - player2Hand.length * cardSpacing / 2;
for (var j = 0; j < player2Hand.length; j++) {
var card2 = player2Hand[j];
card2.x = startX2 + j * cardSpacing;
card2.y = 200;
card2.rotation = Math.PI;
}
// Position top discard card
if (discardPile.length > 0) {
var topCard = discardPile[discardPile.length - 1];
topCard.x = 1024;
topCard.y = 1366;
}
updatePlayableCards();
}
function updatePlayableCards() {
if (discardPile.length === 0) return;
var topCard = discardPile[discardPile.length - 1];
// Update player 1 cards
for (var i = 0; i < player1Hand.length; i++) {
var canPlay = player1Hand[i].canPlayOn(topCard);
player1Hand[i].setPlayable(canPlay);
}
}
function playCard(card) {
if (currentPlayer !== 0) return;
var cardIndex = player1Hand.indexOf(card);
if (cardIndex === -1) return;
// Remove card from hand
player1Hand.splice(cardIndex, 1);
// Add to discard pile
discardPile.push(card);
// Position card on discard pile
card.x = 1024;
card.y = 1366;
LK.getSound('cardPlay').play();
// Handle special cards
if (card.color === 'wild') {
pendingWildCard = card;
colorChooser.visible = true;
return;
}
executeCardEffect(card);
// Check for UNO
if (player1Hand.length === 1) {
// Player should call UNO
LK.setTimeout(function () {
if (player1Hand.length === 1) {
// Penalty for not calling UNO
drawCards(0, 2);
LK.getSound('penalty').play();
}
}, 3000);
}
// Check for win
if (player1Hand.length === 0) {
endRound(0);
return;
}
arrangeCards();
nextTurn();
}
function executeCardEffect(card) {
switch (card.value) {
case 'skip':
// Skip next player
nextTurn();
break;
case 'reverse':
gameDirection *= -1;
break;
case 'draw2':
drawCards(1, 2);
nextTurn();
break;
case 'wilddraw4':
drawCards(1, 4);
nextTurn();
break;
}
}
function chooseWildColor(color) {
if (!pendingWildCard) return;
pendingWildCard.color = color;
colorChooser.visible = false;
executeCardEffect(pendingWildCard);
pendingWildCard = null;
arrangeCards();
nextTurn();
}
function drawCards(player, count) {
for (var i = 0; i < count; i++) {
if (drawPile.length === 0) {
reshuffleDiscardPile();
}
if (drawPile.length > 0) {
var cardData = drawPile.pop();
var newCard = new UnoCard(cardData.color, cardData.value);
game.addChild(newCard);
if (player === 0) {
player1Hand.push(newCard);
} else {
player2Hand.push(newCard);
}
}
}
LK.getSound('cardDraw').play();
arrangeCards();
}
function reshuffleDiscardPile() {
if (discardPile.length <= 1) return;
// Keep top card, shuffle rest back into draw pile
var topCard = discardPile.pop();
while (discardPile.length > 0) {
var card = discardPile.shift();
drawPile.push({
color: card.color,
value: card.value
});
card.destroy();
}
discardPile.push(topCard);
shuffleDeck(drawPile);
}
function nextTurn() {
currentPlayer = (currentPlayer + gameDirection + 2) % 2;
if (currentPlayer === 0) {
currentPlayerText.setText('Player 1 Turn');
} else {
currentPlayerText.setText('Player 2 Turn');
// AI turn
LK.setTimeout(function () {
playAITurn();
}, 1000);
}
updatePlayableCards();
}
function playAITurn() {
if (currentPlayer !== 1) return;
var topCard = discardPile[discardPile.length - 1];
var playableCards = [];
// Find playable cards
for (var i = 0; i < player2Hand.length; i++) {
if (player2Hand[i].canPlayOn(topCard)) {
playableCards.push(i);
}
}
if (playableCards.length > 0) {
// Play a random playable card
var randomIndex = playableCards[Math.floor(Math.random() * playableCards.length)];
var card = player2Hand[randomIndex];
// Remove from hand
player2Hand.splice(randomIndex, 1);
// Add to discard pile
discardPile.push(card);
card.x = 1024;
card.y = 1366;
card.rotation = 0;
LK.getSound('cardPlay').play();
// Handle wild cards
if (card.color === 'wild') {
var colors = ['red', 'blue', 'green', 'yellow'];
card.color = colors[Math.floor(Math.random() * 4)];
}
executeCardEffect(card);
// Check for win
if (player2Hand.length === 0) {
endRound(1);
return;
}
arrangeCards();
nextTurn();
} else {
// Draw a card
drawCards(1, 1);
nextTurn();
}
}
function endRound(winner) {
// Calculate points
var points = 0;
var loserHand = winner === 0 ? player2Hand : player1Hand;
for (var i = 0; i < loserHand.length; i++) {
var card = loserHand[i];
if (typeof card.value === 'number') {
points += card.value;
} else if (card.value === 'skip' || card.value === 'reverse' || card.value === 'draw2') {
points += 20;
} else {
points += 50; // Wild cards
}
}
if (winner === 0) {
player1Score += points;
} else {
player2Score += points;
}
scoreText.setText('Player 1: ' + player1Score + ' Player 2: ' + player2Score);
// Check for game win
if (player1Score >= targetScore) {
LK.showYouWin();
} else if (player2Score >= targetScore) {
LK.showGameOver();
} else {
// Start new round
LK.setTimeout(function () {
startNewRound();
}, 2000);
}
}
function startNewRound() {
// Clear hands and discard pile
for (var i = 0; i < player1Hand.length; i++) {
player1Hand[i].destroy();
}
for (var j = 0; j < player2Hand.length; j++) {
player2Hand[j].destroy();
}
for (var k = 0; k < discardPile.length; k++) {
discardPile[k].destroy();
}
player1Hand = [];
player2Hand = [];
discardPile = [];
drawPile = [];
currentPlayer = 0;
gameDirection = 1;
pendingWildCard = null;
colorChooser.visible = false;
dealCards();
}
// UNO button handler
unoButton.down = function (x, y, obj) {
if (player1Hand.length === 1) {
LK.getSound('unoCall').play();
}
};
// Draw card area (right side of screen)
game.down = function (x, y, obj) {
if (x > 1500 && x < 2048 && y > 1200 && y < 1600 && currentPlayer === 0) {
// Draw card area clicked
var topCard = discardPile[discardPile.length - 1];
var hasPlayableCard = false;
for (var i = 0; i < player1Hand.length; i++) {
if (player1Hand[i].canPlayOn(topCard)) {
hasPlayableCard = true;
break;
}
}
if (!hasPlayableCard) {
drawCards(0, 1);
nextTurn();
}
}
};
// Initialize game
dealCards();
currentPlayerText.setText('Player 1 Turn');