User prompt
quiero que cuando una unidad toque un cuadro lo combierta a su color
User prompt
quiero que los tanques sean mas rapidos que la infanteria y que la infanteria sea mas lenta
User prompt
Please fix the bug: 'Timeout.tick error: tween.to is not a function' in or related to this line: 'tween.to(territorySquare, {' Line Number: 471 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Timeout.tick error: tween.to is not a function' in or related to this line: 'tween.to(territorySquare, {' Line Number: 471
User prompt
soluciona errores
User prompt
quiero que el color de los equipos de los te rritorios sea mas visible ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
quiero que los cuadrados tengan su propia imagen
User prompt
quiero que el territorio sean cuadrados del porte de las ciudades
User prompt
elimina la linea
User prompt
quiero que la linea se modifique de forma asimetrica asi la ciudad destruida
User prompt
quiero que la linea se modifique cuando una ciudad sea destruida
User prompt
quiero que aya una linea que separe el territori de cada ia
User prompt
quiero que las unidades sean un poquito mas grandes
User prompt
quiero que las ciudades no esten superpuesteas
User prompt
quiero que las ciudades esten en lugales randoms
User prompt
quiero que sean 5 ciudades por cada ia
Code edit (1 edits merged)
Please save this source code
User prompt
Europa 1941: AI War
Initial prompt
crea un juego en la que 2 ias se peleen en un mapa con el estilo de europa de 1941, cada ia tiene 3 unidades que puede producir en las ciudades de su territorio, cada ciudad tiene 1000 hp de vida y las 3 unidades diferentes tienen diferentes staks
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (startX, startY, targetX, targetY, damage, faction) {
var self = Container.call(this);
self.x = startX;
self.y = startY;
self.damage = damage;
self.faction = faction;
self.speed = 8;
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
self.maxDistance = distance;
self.traveled = 0;
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.traveled += self.speed;
// Check if bullet reached target area or max distance
if (self.traveled >= self.maxDistance) {
self.explode();
}
};
self.explode = function () {
// Find units in explosion radius
var explosionRadius = 30;
var explosionPlayed = false;
for (var i = 0; i < allUnits.length; i++) {
var unit = allUnits[i];
if (unit.faction !== self.faction && unit.health > 0) {
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
var destroyed = unit.takeDamage(self.damage);
if (destroyed && !explosionPlayed) {
// Play unit-specific destruction sound
var soundName = unit.type + 'Destroy';
LK.getSound(soundName).play();
explosionPlayed = true;
}
}
}
}
// Check cities
var enemyCities = self.faction === 'red' ? blueCities : redCities;
for (var i = 0; i < enemyCities.length; i++) {
var city = enemyCities[i];
if (city.health > 0) {
var dx = city.x - self.x;
var dy = city.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
var destroyed = city.takeDamage(self.damage);
if (destroyed && !explosionPlayed) {
LK.getSound('cityDestroy').play();
explosionPlayed = true;
}
}
}
}
// Remove bullet
for (var i = 0; i < bullets.length; i++) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var City = Container.expand(function (faction) {
var self = Container.call(this);
self.faction = faction;
self.health = 1000;
self.maxHealth = 1000;
self.lastProduction = 0;
self.productionCooldown = 180; // 3 seconds at 60fps
var cityGraphics = self.attachAsset('city', {
anchorX: 0.5,
anchorY: 0.5
});
// Color based on faction
if (faction === 'red') {
cityGraphics.tint = 0xff4444;
} else {
cityGraphics.tint = 0x4444ff;
}
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
// Health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
return true; // City destroyed
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.width = 80 * healthPercent;
return false;
};
self.produceUnit = function () {
if (LK.ticks - self.lastProduction < self.productionCooldown) return;
// Check if we've reached the maximum unit limit per faction
var aliveUnits = 0;
for (var i = 0; i < allUnits.length; i++) {
if (allUnits[i].health > 0 && allUnits[i].faction === self.faction) {
aliveUnits++;
}
}
if (aliveUnits >= 10) return; // Don't produce more units if we have 10 or more per faction
// Choose random unit type
var unitTypes = ['infantry', 'tank', 'artillery'];
var unitType = unitTypes[Math.floor(Math.random() * unitTypes.length)];
var unit = new Unit(unitType, self.faction);
// Find valid position that doesn't overlap with other units
var validPosition = false;
var attempts = 0;
var maxAttempts = 20;
var unitRadius = 40; // Minimum distance between units
while (!validPosition && attempts < maxAttempts) {
var angle = Math.random() * Math.PI * 2;
var distance = 100 + Math.random() * 100;
unit.x = self.x + Math.cos(angle) * distance;
unit.y = self.y + Math.sin(angle) * distance;
// Keep within bounds
unit.x = Math.max(50, Math.min(1998, unit.x));
unit.y = Math.max(50, Math.min(2682, unit.y));
// Check for collision with existing units
validPosition = true;
for (var i = 0; i < allUnits.length; i++) {
var otherUnit = allUnits[i];
if (otherUnit.health > 0) {
var dx = unit.x - otherUnit.x;
var dy = unit.y - otherUnit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < unitRadius) {
validPosition = false;
break;
}
}
}
attempts++;
}
// Only spawn if valid position found
if (validPosition) {
allUnits.push(unit);
game.addChild(unit);
self.lastProduction = LK.ticks;
}
};
self.update = function () {
if (self.health <= 0) return;
self.produceUnit();
};
return self;
});
var Unit = Container.expand(function (type, faction) {
var self = Container.call(this);
self.type = type;
self.faction = faction;
self.target = null;
self.lastShot = 0;
self.health = 100;
self.maxHealth = 100;
self.moveSpeed = 2;
self.range = 100;
self.damage = 20;
self.shootCooldown = 60;
// Set unit stats based on type
if (type === 'infantry') {
self.moveSpeed = 2;
self.health = 60;
self.maxHealth = 60;
self.damage = 15;
self.range = 80;
self.shootCooldown = 40;
} else if (type === 'tank') {
self.moveSpeed = 2.5;
self.health = 120;
self.maxHealth = 120;
self.damage = 30;
self.range = 100;
self.shootCooldown = 60;
} else if (type === 'artillery') {
self.moveSpeed = 1;
self.health = 80;
self.maxHealth = 80;
self.damage = 50;
self.range = 180;
self.shootCooldown = 90;
}
var assetName = type;
if (faction === 'red') {
assetName = 'red' + type.charAt(0).toUpperCase() + type.slice(1);
}
var unitGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Color based on faction
if (faction === 'red') {
unitGraphics.tint = 0xff4444;
} else {
unitGraphics.tint = 0x4444ff;
}
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
// Health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
return true; // Unit destroyed
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.width = 80 * healthPercent;
return false;
};
self.findTarget = function () {
var closestDistance = Infinity;
var closestTarget = null;
// Find closest enemy unit
for (var i = 0; i < allUnits.length; i++) {
var unit = allUnits[i];
if (unit.faction !== self.faction && unit.health > 0) {
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestTarget = unit;
}
}
}
// Check enemy cities
var enemyCities = self.faction === 'red' ? blueCities : redCities;
for (var i = 0; i < enemyCities.length; i++) {
var city = enemyCities[i];
if (city.health > 0) {
var dx = city.x - self.x;
var dy = city.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestTarget = city;
}
}
}
return closestTarget;
};
self.update = function () {
if (self.health <= 0) return;
self.target = self.findTarget();
if (self.target && self.target.health > 0) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.range) {
// Move towards target
var moveX = dx / distance * self.moveSpeed;
var moveY = dy / distance * self.moveSpeed;
// Calculate new position
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check for collision with other units and apply separation
var unitRadius = 45; // Minimum distance between units
var separationForce = {
x: 0,
y: 0
};
var nearbyUnits = 0;
for (var i = 0; i < allUnits.length; i++) {
var otherUnit = allUnits[i];
if (otherUnit !== self && otherUnit.health > 0) {
var otherDx = newX - otherUnit.x;
var otherDy = newY - otherUnit.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
if (otherDistance < unitRadius) {
// Apply separation force
if (otherDistance > 0) {
separationForce.x += otherDx / otherDistance;
separationForce.y += otherDy / otherDistance;
nearbyUnits++;
} else {
// Units are on same position, push in random direction
var randomAngle = Math.random() * Math.PI * 2;
separationForce.x += Math.cos(randomAngle);
separationForce.y += Math.sin(randomAngle);
nearbyUnits++;
}
}
}
}
// Apply separation if needed
if (nearbyUnits > 0) {
separationForce.x /= nearbyUnits;
separationForce.y /= nearbyUnits;
// Normalize and apply separation
var sepLength = Math.sqrt(separationForce.x * separationForce.x + separationForce.y * separationForce.y);
if (sepLength > 0) {
separationForce.x = separationForce.x / sepLength * self.moveSpeed * 0.5;
separationForce.y = separationForce.y / sepLength * self.moveSpeed * 0.5;
newX += separationForce.x;
newY += separationForce.y;
}
}
// Update position
self.x = newX;
self.y = newY;
// Keep units within bounds
self.x = Math.max(40, Math.min(2008, self.x));
self.y = Math.max(40, Math.min(2692, self.y));
} else {
// In range, shoot
if (LK.ticks - self.lastShot > self.shootCooldown) {
self.shoot();
self.lastShot = LK.ticks;
}
}
}
};
self.shoot = function () {
if (!self.target || self.target.health <= 0) return;
var bullet = new Bullet(self.x, self.y, self.target.x, self.target.y, self.damage, self.faction);
bullets.push(bullet);
game.addChild(bullet);
// Play unit-specific shooting sound
var shootSoundName = self.type + 'Shoot';
LK.getSound(shootSoundName).play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Game state
var allUnits = [];
var bullets = [];
var redCities = [];
var blueCities = [];
var gameStarted = false;
var showingMenu = true;
// Add territory background image
var territoryBackground = LK.getAsset('territoryBackground', {
anchorX: 0.5,
anchorY: 0.5
});
territoryBackground.x = 2048 / 2;
territoryBackground.y = 2732 / 2;
game.addChild(territoryBackground);
// UI
var statusText = new Text2('Europa 1941: AI War', {
size: 40,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
// Main Menu UI
var menuBackground = LK.getAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
menuBackground.alpha = 1.0;
// Scale to cover full screen
menuBackground.width = 2048;
menuBackground.height = 2732;
LK.gui.center.addChild(menuBackground);
var menuTitle = LK.getAsset('titleImage', {
anchorX: 0.5,
anchorY: 0.5
});
menuTitle.y = -100;
LK.gui.center.addChild(menuTitle);
var startButton = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
startButton.y = 150;
LK.gui.center.addChild(startButton);
var instructionsText = new Text2('Red vs Blue AI armies\nDestroy all enemy cities to win', {
size: 25,
fill: 0xAAAAA
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.y = 250;
LK.gui.center.addChild(instructionsText);
// Animate start button
function animateStartButton() {
tween(startButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
yoyo: true,
repeat: Infinity
});
}
animateStartButton();
// Play menu music
LK.playMusic('menuMusic');
// BETA text in menu
var betaText = new Text2('BETA', {
size: 80,
fill: 0x0000FF
});
betaText.anchor.set(0, 0);
betaText.x = -900;
betaText.y = -1200;
LK.gui.center.addChild(betaText);
// Red city counter button
var redCityButton = new Container();
var redButtonBg = redCityButton.attachAsset('cityCounterButton', {
anchorX: 0.5,
anchorY: 0.5
});
redButtonBg.tint = 0xff4444;
var redCityText = new Text2('0', {
size: 40,
fill: 0xFFFFFF
});
redCityText.anchor.set(0, 0.5);
redCityText.x = 70;
redCityButton.addChild(redCityText);
redCityButton.x = 180;
redCityButton.y = 100;
LK.gui.topLeft.addChild(redCityButton);
// Blue city counter button
var blueCityButton = new Container();
var blueButtonBg = blueCityButton.attachAsset('cityCounterButton', {
anchorX: 0.5,
anchorY: 0.5
});
blueButtonBg.tint = 0x4444ff;
var blueCityText = new Text2('0', {
size: 40,
fill: 0xFFFFFF
});
blueCityText.anchor.set(0, 0.5);
blueCityText.x = 70;
blueCityButton.addChild(blueCityText);
blueCityButton.x = -180;
blueCityButton.y = 100;
LK.gui.topRight.addChild(blueCityButton);
// Button click handlers
redCityButton.down = function (x, y, obj) {
console.log("Red city button clicked!");
// Add any specific functionality for red city button here
};
blueCityButton.down = function (x, y, obj) {
console.log("Blue city button clicked!");
// Add any specific functionality for blue city button here
};
// Initialize cities
function initializeCities() {
var minDistance = 120; // Minimum distance between cities
// Red cities (left side)
for (var i = 0; i < 5; i++) {
var city = new City('red');
var attempts = 0;
var maxAttempts = 50;
var validPosition = false;
while (!validPosition && attempts < maxAttempts) {
city.x = 150 + Math.random() * 500; // Random x between 150-650
city.y = 200 + Math.random() * 2300; // Random y between 200-2500
validPosition = true;
// Check distance from other red cities
for (var j = 0; j < redCities.length; j++) {
var dx = city.x - redCities[j].x;
var dy = city.y - redCities[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
validPosition = false;
break;
}
}
attempts++;
}
redCities.push(city);
game.addChild(city);
}
// Blue cities (right side)
for (var i = 0; i < 5; i++) {
var city = new City('blue');
var attempts = 0;
var maxAttempts = 50;
var validPosition = false;
while (!validPosition && attempts < maxAttempts) {
city.x = 1400 + Math.random() * 500; // Random x between 1400-1900
city.y = 200 + Math.random() * 2300; // Random y between 200-2500
validPosition = true;
// Check distance from other blue cities
for (var j = 0; j < blueCities.length; j++) {
var dx = city.x - blueCities[j].x;
var dy = city.y - blueCities[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
validPosition = false;
break;
}
}
attempts++;
}
blueCities.push(city);
game.addChild(city);
}
}
function updateUI() {
var redAlive = 0;
var blueAlive = 0;
// Count alive cities
for (var i = 0; i < redCities.length; i++) {
if (redCities[i].health > 0) {
redAlive++;
}
}
for (var i = 0; i < blueCities.length; i++) {
if (blueCities[i].health > 0) {
blueAlive++;
}
}
redCityText.setText(redAlive.toString());
blueCityText.setText(blueAlive.toString());
// Check win conditions
if (redAlive === 0) {
statusText.setText('Blue AI Wins!');
returnToMenu();
} else if (blueAlive === 0) {
statusText.setText('Red AI Wins!');
returnToMenu();
}
}
function cleanupDeadUnits() {
for (var i = allUnits.length - 1; i >= 0; i--) {
if (allUnits[i].health <= 0) {
allUnits[i].destroy();
allUnits.splice(i, 1);
}
}
}
// Function to return to main menu
function returnToMenu() {
// Reset game state
gameStarted = false;
showingMenu = true;
statusText.setText('Europa 1941: AI War');
// Clear all game objects
for (var i = 0; i < allUnits.length; i++) {
allUnits[i].destroy();
}
allUnits = [];
for (var i = 0; i < bullets.length; i++) {
bullets[i].destroy();
}
bullets = [];
for (var i = 0; i < redCities.length; i++) {
redCities[i].destroy();
}
redCities = [];
for (var i = 0; i < blueCities.length; i++) {
blueCities[i].destroy();
}
blueCities = [];
// Show menu elements
menuBackground.visible = true;
menuTitle.visible = true;
startButton.visible = true;
instructionsText.visible = true;
betaText.visible = true;
// Reset UI counters
redCityText.setText('0');
blueCityText.setText('0');
// Stop background music and play menu music
LK.stopMusic();
LK.playMusic('menuMusic');
}
// Function to start the game
function startGame() {
// Hide menu elements
menuBackground.visible = false;
menuTitle.visible = false;
startButton.visible = false;
instructionsText.visible = false;
betaText.visible = false;
showingMenu = false;
// Stop menu music and play background music
LK.stopMusic();
LK.playMusic('backgroundMusic');
// Start game initialization
LK.setTimeout(function () {
initializeCities();
gameStarted = true;
statusText.setText('Battle in Progress...');
}, 500);
}
// Touch handler for menu
game.down = function (x, y, obj) {
if (showingMenu) {
startGame();
}
};
// Game update loop
game.update = function () {
if (showingMenu || !gameStarted) return;
// Update all units
for (var i = 0; i < allUnits.length; i++) {
if (allUnits[i].health > 0) {
allUnits[i].update();
}
}
// Update all cities
for (var i = 0; i < redCities.length; i++) {
redCities[i].update();
}
for (var i = 0; i < blueCities.length; i++) {
blueCities[i].update();
}
// Update all bullets
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
// Cleanup dead units
cleanupDeadUnits();
// Update UI
updateUI();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (startX, startY, targetX, targetY, damage, faction) {
var self = Container.call(this);
self.x = startX;
self.y = startY;
self.damage = damage;
self.faction = faction;
self.speed = 8;
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
self.maxDistance = distance;
self.traveled = 0;
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.traveled += self.speed;
// Check if bullet reached target area or max distance
if (self.traveled >= self.maxDistance) {
self.explode();
}
};
self.explode = function () {
// Find units in explosion radius
var explosionRadius = 30;
var explosionPlayed = false;
for (var i = 0; i < allUnits.length; i++) {
var unit = allUnits[i];
if (unit.faction !== self.faction && unit.health > 0) {
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
var destroyed = unit.takeDamage(self.damage);
if (destroyed && !explosionPlayed) {
// Play unit-specific destruction sound
var soundName = unit.type + 'Destroy';
LK.getSound(soundName).play();
explosionPlayed = true;
}
}
}
}
// Check cities
var enemyCities = self.faction === 'red' ? blueCities : redCities;
for (var i = 0; i < enemyCities.length; i++) {
var city = enemyCities[i];
if (city.health > 0) {
var dx = city.x - self.x;
var dy = city.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
var destroyed = city.takeDamage(self.damage);
if (destroyed && !explosionPlayed) {
LK.getSound('cityDestroy').play();
explosionPlayed = true;
}
}
}
}
// Remove bullet
for (var i = 0; i < bullets.length; i++) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var City = Container.expand(function (faction) {
var self = Container.call(this);
self.faction = faction;
self.health = 1000;
self.maxHealth = 1000;
self.lastProduction = 0;
self.productionCooldown = 180; // 3 seconds at 60fps
var cityGraphics = self.attachAsset('city', {
anchorX: 0.5,
anchorY: 0.5
});
// Color based on faction
if (faction === 'red') {
cityGraphics.tint = 0xff4444;
} else {
cityGraphics.tint = 0x4444ff;
}
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
// Health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
return true; // City destroyed
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.width = 80 * healthPercent;
return false;
};
self.produceUnit = function () {
if (LK.ticks - self.lastProduction < self.productionCooldown) return;
// Check if we've reached the maximum unit limit per faction
var aliveUnits = 0;
for (var i = 0; i < allUnits.length; i++) {
if (allUnits[i].health > 0 && allUnits[i].faction === self.faction) {
aliveUnits++;
}
}
if (aliveUnits >= 10) return; // Don't produce more units if we have 10 or more per faction
// Choose random unit type
var unitTypes = ['infantry', 'tank', 'artillery'];
var unitType = unitTypes[Math.floor(Math.random() * unitTypes.length)];
var unit = new Unit(unitType, self.faction);
// Find valid position that doesn't overlap with other units
var validPosition = false;
var attempts = 0;
var maxAttempts = 20;
var unitRadius = 40; // Minimum distance between units
while (!validPosition && attempts < maxAttempts) {
var angle = Math.random() * Math.PI * 2;
var distance = 100 + Math.random() * 100;
unit.x = self.x + Math.cos(angle) * distance;
unit.y = self.y + Math.sin(angle) * distance;
// Keep within bounds
unit.x = Math.max(50, Math.min(1998, unit.x));
unit.y = Math.max(50, Math.min(2682, unit.y));
// Check for collision with existing units
validPosition = true;
for (var i = 0; i < allUnits.length; i++) {
var otherUnit = allUnits[i];
if (otherUnit.health > 0) {
var dx = unit.x - otherUnit.x;
var dy = unit.y - otherUnit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < unitRadius) {
validPosition = false;
break;
}
}
}
attempts++;
}
// Only spawn if valid position found
if (validPosition) {
allUnits.push(unit);
game.addChild(unit);
self.lastProduction = LK.ticks;
}
};
self.update = function () {
if (self.health <= 0) return;
self.produceUnit();
};
return self;
});
var Unit = Container.expand(function (type, faction) {
var self = Container.call(this);
self.type = type;
self.faction = faction;
self.target = null;
self.lastShot = 0;
self.health = 100;
self.maxHealth = 100;
self.moveSpeed = 2;
self.range = 100;
self.damage = 20;
self.shootCooldown = 60;
// Set unit stats based on type
if (type === 'infantry') {
self.moveSpeed = 2;
self.health = 60;
self.maxHealth = 60;
self.damage = 15;
self.range = 80;
self.shootCooldown = 40;
} else if (type === 'tank') {
self.moveSpeed = 2.5;
self.health = 120;
self.maxHealth = 120;
self.damage = 30;
self.range = 100;
self.shootCooldown = 60;
} else if (type === 'artillery') {
self.moveSpeed = 1;
self.health = 80;
self.maxHealth = 80;
self.damage = 50;
self.range = 180;
self.shootCooldown = 90;
}
var assetName = type;
if (faction === 'red') {
assetName = 'red' + type.charAt(0).toUpperCase() + type.slice(1);
}
var unitGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Color based on faction
if (faction === 'red') {
unitGraphics.tint = 0xff4444;
} else {
unitGraphics.tint = 0x4444ff;
}
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
// Health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
return true; // Unit destroyed
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.width = 80 * healthPercent;
return false;
};
self.findTarget = function () {
var closestDistance = Infinity;
var closestTarget = null;
// Find closest enemy unit
for (var i = 0; i < allUnits.length; i++) {
var unit = allUnits[i];
if (unit.faction !== self.faction && unit.health > 0) {
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestTarget = unit;
}
}
}
// Check enemy cities
var enemyCities = self.faction === 'red' ? blueCities : redCities;
for (var i = 0; i < enemyCities.length; i++) {
var city = enemyCities[i];
if (city.health > 0) {
var dx = city.x - self.x;
var dy = city.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestTarget = city;
}
}
}
return closestTarget;
};
self.update = function () {
if (self.health <= 0) return;
self.target = self.findTarget();
if (self.target && self.target.health > 0) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.range) {
// Move towards target
var moveX = dx / distance * self.moveSpeed;
var moveY = dy / distance * self.moveSpeed;
// Calculate new position
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check for collision with other units and apply separation
var unitRadius = 45; // Minimum distance between units
var separationForce = {
x: 0,
y: 0
};
var nearbyUnits = 0;
for (var i = 0; i < allUnits.length; i++) {
var otherUnit = allUnits[i];
if (otherUnit !== self && otherUnit.health > 0) {
var otherDx = newX - otherUnit.x;
var otherDy = newY - otherUnit.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
if (otherDistance < unitRadius) {
// Apply separation force
if (otherDistance > 0) {
separationForce.x += otherDx / otherDistance;
separationForce.y += otherDy / otherDistance;
nearbyUnits++;
} else {
// Units are on same position, push in random direction
var randomAngle = Math.random() * Math.PI * 2;
separationForce.x += Math.cos(randomAngle);
separationForce.y += Math.sin(randomAngle);
nearbyUnits++;
}
}
}
}
// Apply separation if needed
if (nearbyUnits > 0) {
separationForce.x /= nearbyUnits;
separationForce.y /= nearbyUnits;
// Normalize and apply separation
var sepLength = Math.sqrt(separationForce.x * separationForce.x + separationForce.y * separationForce.y);
if (sepLength > 0) {
separationForce.x = separationForce.x / sepLength * self.moveSpeed * 0.5;
separationForce.y = separationForce.y / sepLength * self.moveSpeed * 0.5;
newX += separationForce.x;
newY += separationForce.y;
}
}
// Update position
self.x = newX;
self.y = newY;
// Keep units within bounds
self.x = Math.max(40, Math.min(2008, self.x));
self.y = Math.max(40, Math.min(2692, self.y));
} else {
// In range, shoot
if (LK.ticks - self.lastShot > self.shootCooldown) {
self.shoot();
self.lastShot = LK.ticks;
}
}
}
};
self.shoot = function () {
if (!self.target || self.target.health <= 0) return;
var bullet = new Bullet(self.x, self.y, self.target.x, self.target.y, self.damage, self.faction);
bullets.push(bullet);
game.addChild(bullet);
// Play unit-specific shooting sound
var shootSoundName = self.type + 'Shoot';
LK.getSound(shootSoundName).play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Game state
var allUnits = [];
var bullets = [];
var redCities = [];
var blueCities = [];
var gameStarted = false;
var showingMenu = true;
// Add territory background image
var territoryBackground = LK.getAsset('territoryBackground', {
anchorX: 0.5,
anchorY: 0.5
});
territoryBackground.x = 2048 / 2;
territoryBackground.y = 2732 / 2;
game.addChild(territoryBackground);
// UI
var statusText = new Text2('Europa 1941: AI War', {
size: 40,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
// Main Menu UI
var menuBackground = LK.getAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
menuBackground.alpha = 1.0;
// Scale to cover full screen
menuBackground.width = 2048;
menuBackground.height = 2732;
LK.gui.center.addChild(menuBackground);
var menuTitle = LK.getAsset('titleImage', {
anchorX: 0.5,
anchorY: 0.5
});
menuTitle.y = -100;
LK.gui.center.addChild(menuTitle);
var startButton = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
startButton.y = 150;
LK.gui.center.addChild(startButton);
var instructionsText = new Text2('Red vs Blue AI armies\nDestroy all enemy cities to win', {
size: 25,
fill: 0xAAAAA
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.y = 250;
LK.gui.center.addChild(instructionsText);
// Animate start button
function animateStartButton() {
tween(startButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
yoyo: true,
repeat: Infinity
});
}
animateStartButton();
// Play menu music
LK.playMusic('menuMusic');
// BETA text in menu
var betaText = new Text2('BETA', {
size: 80,
fill: 0x0000FF
});
betaText.anchor.set(0, 0);
betaText.x = -900;
betaText.y = -1200;
LK.gui.center.addChild(betaText);
// Red city counter button
var redCityButton = new Container();
var redButtonBg = redCityButton.attachAsset('cityCounterButton', {
anchorX: 0.5,
anchorY: 0.5
});
redButtonBg.tint = 0xff4444;
var redCityText = new Text2('0', {
size: 40,
fill: 0xFFFFFF
});
redCityText.anchor.set(0, 0.5);
redCityText.x = 70;
redCityButton.addChild(redCityText);
redCityButton.x = 180;
redCityButton.y = 100;
LK.gui.topLeft.addChild(redCityButton);
// Blue city counter button
var blueCityButton = new Container();
var blueButtonBg = blueCityButton.attachAsset('cityCounterButton', {
anchorX: 0.5,
anchorY: 0.5
});
blueButtonBg.tint = 0x4444ff;
var blueCityText = new Text2('0', {
size: 40,
fill: 0xFFFFFF
});
blueCityText.anchor.set(0, 0.5);
blueCityText.x = 70;
blueCityButton.addChild(blueCityText);
blueCityButton.x = -180;
blueCityButton.y = 100;
LK.gui.topRight.addChild(blueCityButton);
// Button click handlers
redCityButton.down = function (x, y, obj) {
console.log("Red city button clicked!");
// Add any specific functionality for red city button here
};
blueCityButton.down = function (x, y, obj) {
console.log("Blue city button clicked!");
// Add any specific functionality for blue city button here
};
// Initialize cities
function initializeCities() {
var minDistance = 120; // Minimum distance between cities
// Red cities (left side)
for (var i = 0; i < 5; i++) {
var city = new City('red');
var attempts = 0;
var maxAttempts = 50;
var validPosition = false;
while (!validPosition && attempts < maxAttempts) {
city.x = 150 + Math.random() * 500; // Random x between 150-650
city.y = 200 + Math.random() * 2300; // Random y between 200-2500
validPosition = true;
// Check distance from other red cities
for (var j = 0; j < redCities.length; j++) {
var dx = city.x - redCities[j].x;
var dy = city.y - redCities[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
validPosition = false;
break;
}
}
attempts++;
}
redCities.push(city);
game.addChild(city);
}
// Blue cities (right side)
for (var i = 0; i < 5; i++) {
var city = new City('blue');
var attempts = 0;
var maxAttempts = 50;
var validPosition = false;
while (!validPosition && attempts < maxAttempts) {
city.x = 1400 + Math.random() * 500; // Random x between 1400-1900
city.y = 200 + Math.random() * 2300; // Random y between 200-2500
validPosition = true;
// Check distance from other blue cities
for (var j = 0; j < blueCities.length; j++) {
var dx = city.x - blueCities[j].x;
var dy = city.y - blueCities[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
validPosition = false;
break;
}
}
attempts++;
}
blueCities.push(city);
game.addChild(city);
}
}
function updateUI() {
var redAlive = 0;
var blueAlive = 0;
// Count alive cities
for (var i = 0; i < redCities.length; i++) {
if (redCities[i].health > 0) {
redAlive++;
}
}
for (var i = 0; i < blueCities.length; i++) {
if (blueCities[i].health > 0) {
blueAlive++;
}
}
redCityText.setText(redAlive.toString());
blueCityText.setText(blueAlive.toString());
// Check win conditions
if (redAlive === 0) {
statusText.setText('Blue AI Wins!');
returnToMenu();
} else if (blueAlive === 0) {
statusText.setText('Red AI Wins!');
returnToMenu();
}
}
function cleanupDeadUnits() {
for (var i = allUnits.length - 1; i >= 0; i--) {
if (allUnits[i].health <= 0) {
allUnits[i].destroy();
allUnits.splice(i, 1);
}
}
}
// Function to return to main menu
function returnToMenu() {
// Reset game state
gameStarted = false;
showingMenu = true;
statusText.setText('Europa 1941: AI War');
// Clear all game objects
for (var i = 0; i < allUnits.length; i++) {
allUnits[i].destroy();
}
allUnits = [];
for (var i = 0; i < bullets.length; i++) {
bullets[i].destroy();
}
bullets = [];
for (var i = 0; i < redCities.length; i++) {
redCities[i].destroy();
}
redCities = [];
for (var i = 0; i < blueCities.length; i++) {
blueCities[i].destroy();
}
blueCities = [];
// Show menu elements
menuBackground.visible = true;
menuTitle.visible = true;
startButton.visible = true;
instructionsText.visible = true;
betaText.visible = true;
// Reset UI counters
redCityText.setText('0');
blueCityText.setText('0');
// Stop background music and play menu music
LK.stopMusic();
LK.playMusic('menuMusic');
}
// Function to start the game
function startGame() {
// Hide menu elements
menuBackground.visible = false;
menuTitle.visible = false;
startButton.visible = false;
instructionsText.visible = false;
betaText.visible = false;
showingMenu = false;
// Stop menu music and play background music
LK.stopMusic();
LK.playMusic('backgroundMusic');
// Start game initialization
LK.setTimeout(function () {
initializeCities();
gameStarted = true;
statusText.setText('Battle in Progress...');
}, 500);
}
// Touch handler for menu
game.down = function (x, y, obj) {
if (showingMenu) {
startGame();
}
};
// Game update loop
game.update = function () {
if (showingMenu || !gameStarted) return;
// Update all units
for (var i = 0; i < allUnits.length; i++) {
if (allUnits[i].health > 0) {
allUnits[i].update();
}
}
// Update all cities
for (var i = 0; i < redCities.length; i++) {
redCities[i].update();
}
for (var i = 0; i < blueCities.length; i++) {
blueCities[i].update();
}
// Update all bullets
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
// Cleanup dead units
cleanupDeadUnits();
// Update UI
updateUI();
};
con estilo de hoi4
prollectil de un flak 8,8cm. In-Game asset. 2d. High contrast. No shadows
boton de inicio al estilo hoi4. In-Game asset. 2d. High contrast. No shadows
QUE LAS LETRAS TENGAN UN COLOR MAS LLAMATIVO
SOLDADOS SOVIETICOS. In-Game asset. 2d. High contrast. No shadows
tanque t34-85. In-Game asset. 2d. High contrast. No shadows
artilleria sobietica yag 10 g. In-Game asset. 2d. High contrast. No shadows
mas cuadros