Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
when ball isfalling, and reaches courtTopBoundary, then its x should follow a sinusoidal curve
Code edit (5 edits merged)
Please save this source code
User prompt
Curent code : ´´´ if (self.isFalling) { debugTxt.setText("Falling"); // Apply gravity self.speedY += self.gravity; // Move the ball self.y += self.speedY; // Check for ground collision in a perspective view var courtBounceY = courtBottomY - (self.x - court.x) * 0.1; // Simulate perspective bounce effect if (self.y > courtBounceY) { self.y = courtBounceY; // Reverse direction with damping for bounce effect self.speedY *= -0.5; } // Check if the ball has almost stopped moving if (Math.abs(self.speedY) < 0.01) { self.isFalling = false; self.isShot = false; self.speedY = 0; } } ´´´ Request : Currently, the ball falls straight down, but it should realistically bounce multiple times according to the court's perspective. In ball.update when isFalling : Please implement gravity and bounce mechanics to reflect the perspective of the basketball court. Use z coordinate for 3rd dimension to make that. Suppose thre court is a plane viewed from a 45° angle
User prompt
In ball update when falling make multiple parabolic moves
User prompt
In ball.update when isFalling : Please implement gravity and bounce mechanics to reflect the perspective of the basketball court. Currently, the ball falls straight down, but it should realistically bounce multiple times according to the court's perspective. Use z coordinate for 3rd dimension to make that. Supose thre court is a plane viewed from a 45° angle.
User prompt
In ball.update when isFalling : Please implement gravity and bounce mechanics to reflect the perspective of the basketball court. Currently, the ball falls straight down, but it should realistically bounce multiple times according to the court's perspective. Use fake z coordinate for 3rd dimension to make make calculation the convert it to 2d x,y.
User prompt
In ball.update when isFalling : Please implement gravity and bounce mechanics to reflect the perspective of the basketball court. Currently, the ball falls straight down, but it should realistically bounce multiple times according to the court's perspective. Use z coordinate for 3rd dimension to make that.
User prompt
In ball.update when isFalling : Please implement gravity and bounce mechanics to reflect the perspective of the basketball court. Currently, the ball falls straight down, but it should realistically bounce multiple times according to the court's perspective.
User prompt
the game simulates a perspective view of a court so in ball.update when ball isFalling, the ball should bounce on the court, not fall directly at the bottom of the screen
User prompt
the game simulates a perspective view of a court so in ball.update when isFalling, the ball bounce on the court, not fall directly at the bottom
Code edit (1 edits merged)
Please save this source code
Code edit (11 edits merged)
Please save this source code
User prompt
add a mesureFlag at x=0, y=2000
Code edit (1 edits merged)
Please save this source code
Code edit (8 edits merged)
Please save this source code
User prompt
when player moves update debugtxt whith his position
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught ReferenceError: playerHead1 is not defined' in or related to this line: 'var debugTxt = new Text2("Player Height: " + playerHead1.height, {' Line Number: 853
User prompt
ini debugTxt with player's height
Code edit (1 edits merged)
Please save this source code
User prompt
update DebugTxt with player position when he moves
User prompt
update DebugTxt with player position
Code edit (4 edits merged)
Please save this source code
/**** 
* Classes
****/ 
// Assets will be automatically created based on usage in the code.
// Ball class for the basketball
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballGraphics = self.attachAsset('basketball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.followingSpeed = 1.0; // Increased speed when following target line
	self.speedY = 0;
	self.gravity = 0.5;
	self.isShot = false;
	self.isFollowTrajectory = false;
	self.isFalling = false;
	self.currentPlayer = null; // New property to track the current player holding the ball
	self.shoot = function (power, angle) {
		self.speedX = Math.cos(angle) * power;
		self.speedY = Math.sin(angle) * -power; // Negate Y to move up
		self.isShot = true;
	};
	self.shootBall = function () {
		console.log("Executing shootBall ", currentTrajectory);
		if (!currentTrajectory || currentTrajectory.length === 0) {
			console.log("No currentTrajectory");
			return;
		}
		if (self.currentPlayer) {
			self.currentPlayer.hasBall = false;
			self.currentPlayer = null;
		}
		self.isFollowTrajectory = true;
		self.isShot = true;
	};
	// self.shootBall = function (ptX, ptY) {
	// 	console.log("Executing shootBall ", ptX, ptY);
	// 	if (self.currentPlayer) {
	// 		self.currentPlayer.hasBall = false;
	// 		self.currentPlayer = null;
	// 	}
	// 	// Calculate the trajectory for the ball to reach the hoop
	// 	var dx = ptX - self.x;
	// 	var dy = ptY - self.y;
	// 	var distance = Math.sqrt(dx * dx + dy * dy);
	// 	var angle = Math.atan2(dy, dx);
	// 	var power = Math.sqrt(distance) * 0.8; // Adjust power based on distance
	// 	self.speedX = Math.cos(angle) * power;
	// 	self.speedY = Math.sin(angle) * -power; // Negate Y to move up
	// 	self.isShot = true;
	// };
	self.update = function () {
		if (self.isShot) {
			if (self.isFollowTrajectory && currentTrajectory && currentTrajectory.length > 0) {
				// Calculate progressive movement towards the next point in the trajectory
				var nextPoint = currentTrajectory[0];
				var dx = nextPoint.x - self.x;
				var dy = nextPoint.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				console.log("dx,dy=" + dx, dy, " distance =", distance);
				if (distance < 5) {
					// If close enough to the next point, move to the next point and remove it from the trajectory
					self.x = nextPoint.x;
					self.y = nextPoint.y;
					currentTrajectory.shift();
					if (currentTrajectory.length === 0) {
						self.isFollowTrajectory = false;
						self.isFalling = true;
					}
				} else {
					// Otherwise, move progressively towards the next point
					debugTxt.setText("following");
					self.x += dx * self.followingSpeed;
					self.y += dy * self.followingSpeed;
				}
			} else if (self.isFalling) {
				debugTxt.setText("Falling");
				// Apply gravity with perspective effect
				var fakeZ = self.y - courtBottomY; // Fake Z coordinate for 3D effect
				self.speedY += self.gravity - fakeZ * 0.005; // Gravity decreases with "height"
				// Move the ball
				self.y += self.speedY;
				// Check for ground collision in a perspective view
				var courtBounceY = courtBottomY - (self.x - court.x) * 0.1; // Simulate perspective bounce effect
				if (self.y > courtBounceY) {
					self.y = courtBounceY;
					// Reverse direction with damping for bounce effect, increase damping with each bounce
					self.speedY *= -0.7;
				}
				// Check if the ball has almost stopped moving or is below a minimal "height"
				if (Math.abs(self.speedY) < 0.1 || fakeZ > -10) {
					self.isFalling = false;
					self.isShot = false;
					self.speedY = 0;
				}
			} else {
				debugTxt.setText("wait");
			}
		}
	};
	self.reset = function () {
		self.x = 300; //1024; // Center X
		self.y = 2000; // Starting Y 500 -> 2565
		self.isShot = false;
		self.speedY = 0;
	};
});
// Hoop class for the basketball hoop
var Hoop = Container.expand(function () {
	var self = Container.call(this);
	var hoopGraphics = self.attachAsset('hoop', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.setPosition = function () {
		self.x = 1024; // Center X
		self.y = 200; // Hoop Y position
	};
});
// Player class for the player
var Player = Container.expand(function () {
	var self = Container.call(this);
	self.hasBall = false; // New property to indicate if the player has the ball
	self.currentPosture = ""; // New property to store the name of the current posture
	self.isChangingPosture = false; // 0 when idle or moving down, 1 when moving up
	self.nextPosture = null;
	self.isMovingUp = 0; // 0 when idle or moving down, 1 when moving up
	self.head = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 1
	});
	self.eyes = self.attachAsset('eyes', {
		anchorX: 0.5,
		anchorY: 0.75,
		scaleX: 0.8,
		scaleY: 1
	});
	self.rightArm = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 1,
		scaleX: 0.5,
		scaleY: 1.5
	});
	self.rightHand = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.75,
		scaleY: 0.5
	});
	self.leftArm = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 1,
		scaleX: 0.5,
		scaleY: 1.5
	});
	self.leftHand = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.75,
		scaleY: 0.5
	});
	self.trunk = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.5,
		scaleY: 2.0
	});
	self.rightLeg = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.5,
		scaleY: 2
	});
	self.rightFoot = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.75,
		scaleY: 0.5
	});
	self.leftLeg = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.5,
		scaleY: 2
	});
	self.leftFoot = self.attachAsset('bodyPart', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.75,
		scaleY: 0.5
	});
	self.updatePosture = function () {
		var speed = 0.2; //0.1; // Speed of transition
		if (!this.targetPosture) {
			return;
		}
		// Check if the target posture for hands and legs is reached
		//console.log("this.targetPosture: " + this.targetPosture.name + " :  this.rightHand.x: " + this.rightHand.x, " this.targetPosture.rightHand.x: " + this.targetPosture.rightHand.x);
		var handsAndLegsReached = Math.abs(this.rightHand.x - this.targetPosture.rightHand.x) < 1 && Math.abs(this.rightHand.y - this.targetPosture.rightHand.y) < 1 && Math.abs(this.leftHand.x - this.targetPosture.leftHand.x) < 1 && Math.abs(this.leftHand.y - this.targetPosture.leftHand.y) < 1 && Math.abs(this.rightLeg.x - this.targetPosture.rightLeg.x) < 1 && Math.abs(this.rightLeg.y - this.targetPosture.rightLeg.y) < 1 && Math.abs(this.leftLeg.x - this.targetPosture.leftLeg.x) < 1 && Math.abs(this.leftLeg.y - this.targetPosture.leftLeg.y) < 1 && Math.abs(this.head.x - this.targetPosture.head.x) < 1 && Math.abs(this.head.y - this.targetPosture.head.y) < 1 && Math.abs(this.eyes.x - this.targetPosture.eyes.x) < 1 && Math.abs(this.eyes.y - this.targetPosture.eyes.y) < 1 && Math.abs(this.rightFoot.x - this.targetPosture.rightFoot.x) < 1 && Math.abs(this.rightFoot.y - this.targetPosture.rightFoot.y) < 1 && Math.abs(this.leftFoot.x - this.targetPosture.leftFoot.x) < 1 && Math.abs(this.leftFoot.y - this.targetPosture.leftFoot.y) < 1;
		if (handsAndLegsReached) {
			//console.log("handsAndLegsReached !");
			// Update currentPosture to the name of the targetPosture when hands and legs posture is reached
			this.currentPosture = this.targetPosture.name;
			this.targetPosture = null;
			self.isChangingPosture = false;
			if (self.nextPosture) {
				self.setPosture(self.nextPosture);
			}
			return;
		} else {
			self.isChangingPosture = true;
		}
		if (this.targetPosture && this.targetPosture.head) {
			this.head.x += (this.targetPosture.head.x - this.head.x) * speed;
		}
		if (this.targetPosture && this.targetPosture.eyes) {
			this.eyes.x += (this.targetPosture.eyes.x - this.eyes.x) * speed;
			this.eyes.y += (this.targetPosture.eyes.y - this.eyes.y) * speed;
			this.eyes.visible = enableEye && !self.isMovingUp && !isThrowingMode;
		}
		this.head.y += (this.targetPosture.head.y - this.head.y) * speed;
		this.rightArm.x += (this.targetPosture.rightArm.x - this.rightArm.x) * speed;
		this.rightArm.y += (this.targetPosture.rightArm.y - this.rightArm.y) * speed;
		this.rightHand.x += (this.targetPosture.rightHand.x - this.rightHand.x) * speed;
		this.rightHand.y += (this.targetPosture.rightHand.y - this.rightHand.y) * speed;
		this.leftArm.x += (this.targetPosture.leftArm.x - this.leftArm.x) * speed;
		this.leftArm.y += (this.targetPosture.leftArm.y - this.leftArm.y) * speed;
		this.leftHand.x += (this.targetPosture.leftHand.x - this.leftHand.x) * speed;
		this.leftHand.y += (this.targetPosture.leftHand.y - this.leftHand.y) * speed;
		this.trunk.x += (this.targetPosture.trunk.x - this.trunk.x) * speed;
		this.trunk.y += (this.targetPosture.trunk.y - this.trunk.y) * speed;
		this.rightLeg.x += (this.targetPosture.rightLeg.x - this.rightLeg.x) * speed;
		this.rightLeg.y += (this.targetPosture.rightLeg.y - this.rightLeg.y) * speed;
		this.rightFoot.x += (this.targetPosture.rightFoot.x - this.rightFoot.x) * speed;
		this.rightFoot.y += (this.targetPosture.rightFoot.y - this.rightFoot.y) * speed;
		this.leftLeg.x += (this.targetPosture.leftLeg.x - this.leftLeg.x) * speed;
		this.leftLeg.y += (this.targetPosture.leftLeg.y - this.leftLeg.y) * speed;
		this.leftFoot.x += (this.targetPosture.leftFoot.x - this.leftFoot.x) * speed;
		this.leftFoot.y += (this.targetPosture.leftFoot.y - this.leftFoot.y) * speed;
	};
	self.updatePosition = function () {
		self.isMoving = false;
		self.speedX = 0;
		self.speedY = 0;
		if (joystickDrag) {
			if (isThrowingMode) {} else {
				self.isMoving = true;
				var dx = joystick.x - joystickBasePosition.x;
				var dy = joystick.y - joystickBasePosition.y;
				self.speedX = dx * 0.15; // Adjust speed factor as needed
				self.speedY = dy * 0.15; // Adjust speed factor as needed
			}
		}
		// Apply speed
		self.x += self.speedX;
		self.y += self.speedY;
		debugTxt.setText("Player X: " + self.x.toFixed(2) + ", Y: " + self.y.toFixed(2));
		//console.log("Player speedY: ", self.speedY); // Log player's vertical speed
		self.isMovingUp = self.speedY < 0 ? 1 : 0;
		self.eyes.visible = enableEye && !self.isMovingUp && !isThrowingMode;
		// Boundary checks
		if (self.x < courtLeftBoundary + self.width / 2) {
			self.x = courtLeftBoundary + self.width / 2;
		} else if (self.x > courtRightBoundary - self.width / 2) {
			self.x = courtRightBoundary - self.width / 2;
		}
		if (self.y < courtTopBoundary - 0) {
			self.y = courtTopBoundary - 0;
		} else if (self.y > courtBottomBoundary - 275) {
			self.y = courtBottomBoundary - 275;
		}
		// Posture updates based on movement
		if (self.isMoving) {
			var currentTick = LK.ticks;
			if (currentTick % 20 < 10) {
				self.setPosture(self.hasBall ? runningUpWithBall1 : runningUp1);
			} else {
				self.setPosture(self.hasBall ? runningUpWithBall2 : runningUp2);
			}
		} else {
			if (self.hasBall) {
				if (isThrowingMode) {} else {
					self.setPosture(Math.abs(ball.y - self.y) > 150 ? dribblingPosture1 : dribblingPosture2);
				}
			} else {
				//console.log("No ball => idle" + self.hasBall);
				self.setPosture(idlePosture);
			}
		}
	};
	self.setPosture = function (newPosture) {
		//console.log("Entering setPosture " + self.currentPosture + " => " + newPosture.name);
		if (self.isChangingPosture) {
			//console.log("Already changing");
			// Store next posture for when target one is reached
			self.nextPosture = newPosture;
			return;
		}
		if (self.nextPosture) {
			// If a next posture is set, use it as target
			newPosture = self.nextPosture;
			self.nextPosture = null;
		}
		if (self.currentPosture != newPosture.name) {
			self.targetPosture = newPosture;
		} else {
			//console.log("Already in posture");
		}
	};
});
// Class for the targeting line made of targetDots
var TargetingLine = Container.expand(function () {
	var self = Container.call(this);
	self.dots = [];
	self.steps = 20;
	// Initialize 10 dots for the targeting line
	for (var i = 0; i < self.steps; i++) {
		var dot = self.attachAsset('targetDot', {
			anchorX: 0.5,
			anchorY: 0.5,
			visible: false // Initially not visible
		});
		self.dots.push(dot);
	}
	// Method to update the targeting line
	self.updateLine = function (startX, startY, endX, endY) {
		// Controls only the dots positions, not their visibility
		if (this.isUpdating) {
			return;
		}
		this.isUpdating = true;
		// Calculate line direction and distance
		var dx = endX - startX;
		var dy = endY - startY;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var parabolRatio = Math.min(Math.max(Math.abs(dy / 20), 10), 40);
		//console.log("dy: " + (dy + game.height * 0.25) + ", ParabolRatio: " + parabolRatio);
		var stepX = dx / self.steps;
		var stepY = dy / self.steps;
		// Update positions of existing dots along the line
		for (var i = 0; i < self.steps; i++) {
			if (self.dots[i]) {
				// Calculate offset to only go up
				var offset = -parabolRatio * i * Math.sin(Math.PI / self.steps * i);
				self.dots[i].x = startX + stepX * i;
				self.dots[i].y = startY + stepY * i + offset;
			}
		}
		this.isUpdating = false;
		// Store dots coordinates in currentTrajectory
		currentTrajectory = self.dots.map(function (dot) {
			return {
				x: dot.x,
				y: dot.y
			};
		});
	};
	// Method to hide the targeting line
	self.showLine = function () {
		// Controls only the dots visibility, not their positions
		self.visible = true;
		self.dots.forEach(function (dot) {
			dot.visible = true;
		});
	};
	self.hideLine = function () {
		// Controls only the dots visibility, not their positions
		self.visible = false;
		self.dots.forEach(function (dot) {
			dot.visible = false;
		});
	};
});
/**** 
* Initialize Game
****/ 
// Player positions
var game = new LK.Game({
	backgroundColor: 0x000000 // Sky blue background
});
/**** 
* Game Code
****/ 
// Create and position the court
var courtTopY = 750;
var courtCenterY = 1525; // court asset height 2056/2+750 (top) = 1778 ~= 1700 | v2 : 2250/2+750 = 1875
var courtBottomY = 2325;
var court = game.addChild(LK.getAsset('Court', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: courtCenterY,
	scaleX: 1.009,
	tint: 0xb27747 //AE4E00 // Brown tint
	// Stretch to fit the height of the screen
	//scaleY: 2732 / 1056.89 // Stretch to fit the height of the screen
}));
var targetPointXOffsetDirection = 1;
var targetPointXOffset = 0;
var targetPointXOffsetIncrement = 5; // Increment or decrement offset by 10
var targetPointXOffsetBounds = 220; // Bounds for changing direction
var currentTrajectory = [];
// Define court boundaries as global variables
var courtTopBoundary = 520;
var courtBottomBoundary = 2325;
var courtLeftBoundary = 0;
var courtRightBoundary = 2048;
var mesureFlag = game.addChild(LK.getAsset('mesureFlag', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 50,
	y: 2325
}));
// Create and position the joystick
var joystick = game.addChild(LK.getAsset('joystick', {
	anchorX: 0.5,
	anchorY: 0.5,
	alpha: 0.75,
	x: 2048 / 2,
	// Center X
	y: 2732 - 250
}));
/******* Retro Basket ********
A retro basketball game.
It's a one vs one basketball game.
Ball is lanched in the middle.
Players must run and catch it, then throw it in the hoop.
*****************************/
var idlePosture = {
	name: "idlePosture",
	x: 1024,
	y: 2000,
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 110,
		y: 50
	},
	rightHand: {
		x: 125,
		y: 30
	},
	leftArm: {
		x: -110,
		y: 50
	},
	leftHand: {
		x: -120,
		y: 30
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 37.5,
		y: 150
	},
	rightFoot: {
		x: 50,
		y: 250
	},
	leftLeg: {
		x: -37.5,
		y: 150
	},
	leftFoot: {
		x: -50,
		y: 250
	}
};
var dribblingPosture1 = {
	name: "dribblingPosture1",
	x: 1024,
	// Center X
	y: 2000,
	// Player Y position
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 90,
		y: 50 // Adjusted from -20 to 50
	},
	rightHand: {
		x: -90,
		y: 30
	},
	leftArm: {
		x: -90,
		y: 50 // Adjusted from -20 to 50
	},
	leftHand: {
		x: 90,
		y: 30
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 40,
		y: 150
	},
	rightFoot: {
		x: 50,
		y: 250
	},
	leftLeg: {
		x: -40,
		y: 150
	},
	leftFoot: {
		x: -50,
		y: 250
	}
};
var dribblingPosture2 = {
	name: "dribblingPosture2",
	x: 1024,
	// Center X
	y: 2000,
	// Player Y position
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 90,
		y: 50 // Adjusted from -20 to 50
	},
	rightHand: {
		x: -90,
		y: 50
	},
	leftArm: {
		x: -90,
		y: 50 // Adjusted from -20 to 50
	},
	leftHand: {
		x: 90,
		y: 50
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 40,
		y: 150
	},
	rightFoot: {
		x: 50,
		y: 250
	},
	leftLeg: {
		x: -40,
		y: 150
	},
	leftFoot: {
		x: -50,
		y: 250
	}
};
var runningUp1 = {
	name: "runningUp1",
	x: 1024,
	// Center X
	y: 2000,
	// Player Y position
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 90,
		y: 50 // Adjusted from -20 to 50 by adding 70
	},
	rightHand: {
		x: 105,
		y: 30
	},
	leftArm: {
		x: -90,
		y: 50
	},
	leftHand: {
		x: -105,
		y: 30
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 40,
		y: 100
	},
	rightFoot: {
		x: 50,
		y: 200
	},
	leftLeg: {
		x: -40,
		y: 150
	},
	leftFoot: {
		x: -50,
		y: 250
	}
};
var runningUp2 = {
	name: "runningUp2",
	x: 1024,
	// Center X
	y: 2000,
	// Player Y position
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 80,
		y: 50 // Adjusted from -20 to 50 by adding 70
	},
	rightHand: {
		x: 95,
		y: 30
	},
	leftArm: {
		x: -80,
		y: 50
	},
	leftHand: {
		x: -95,
		y: 30
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 40,
		y: 150
	},
	rightFoot: {
		x: 50,
		y: 250
	},
	leftLeg: {
		x: -40,
		y: 100
	},
	leftFoot: {
		x: -50,
		y: 200
	}
};
var runningUpWithBall1 = {
	name: "runningUpWithBall1",
	x: 1024,
	// Center X
	y: 2000,
	// Player Y position
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 90,
		y: 20 // Adjusted from -20 to 50 by adding 70
	},
	rightHand: {
		x: -0,
		y: -20
	},
	leftArm: {
		x: -90,
		y: 20
	},
	leftHand: {
		x: 0,
		y: -20
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 40,
		y: 100
	},
	rightFoot: {
		x: 50,
		y: 200
	},
	leftLeg: {
		x: -40,
		y: 150
	},
	leftFoot: {
		x: -50,
		y: 250
	}
};
var runningUpWithBall2 = {
	name: "runningUpWithBall2",
	x: 1024,
	// Center X
	y: 2000,
	// Player Y position
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 80,
		y: -20 // Adjusted from -90 to -20 by adding 70
	},
	rightHand: {
		x: 5,
		y: 15
	},
	leftArm: {
		x: -80,
		y: -20
	},
	leftHand: {
		x: 5,
		y: 15
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 40,
		y: 150
	},
	rightFoot: {
		x: 50,
		y: 250
	},
	leftLeg: {
		x: -40,
		y: 100
	},
	leftFoot: {
		x: -50,
		y: 200
	}
};
var throwingPosture = {
	name: "throwingPosture",
	x: 1024,
	y: 2000,
	head: {
		x: 0,
		y: -160
	},
	eyes: {
		x: 0,
		y: -160
	},
	rightArm: {
		x: 100,
		y: -120
	},
	rightHand: {
		x: 100,
		y: -250 // Set the right hand at the top of the right arm
	},
	leftArm: {
		x: -100,
		y: -120
	},
	leftHand: {
		x: -100,
		y: -250 // Set the left hand at the top of the left arm
	},
	trunk: {
		x: 0,
		y: 0
	},
	rightLeg: {
		x: 37.5,
		y: 150
	},
	rightFoot: {
		x: 50,
		y: 250
	},
	leftLeg: {
		x: -37.5,
		y: 150
	},
	leftFoot: {
		x: -50,
		y: 250
	}
};
var player = game.addChild(new Player());
player.x = 800; //2048 / 2; // Center X
player.y = 2000; //2732 / 2; // Center Y
player.setPosture(idlePosture);
var ball = game.addChild(new Ball());
ball.reset();
var hoop = game.addChild(new Hoop());
hoop.setPosition();
var score = 0;
var debugTxt = new Text2("Court Top: " + (court.y - court.height / 2) + ", Bottom: " + (court.y + court.height / 2), {
	size: 50,
	fill: "#ffffff"
});
debugTxt.x = 20;
debugTxt.y = 20;
LK.gui.topLeft.addChild(debugTxt);
var scoreTxt = new Text2("0" + score.toString(), {
	size: 150,
	fill: "#ffffff"
});
scoreTxt.x = -180;
scoreTxt.y = -10;
var enableEye = true;
LK.gui.topRight.addChild(scoreTxt);
var joystickBasePosition = {
	x: joystick.x,
	y: joystick.y
};
var joystickDrag = false;
var lastTouchDownTime = 0; // Timestamp of the last touch down event
var touchTapThreshold = 200; // Milliseconds within which a touch is considered a tap
var isTapGesture = false; // Flag to differentiate between tap and drag gestures
var isThrowingMode = 0; // 0 = Move mode; 1 = Throw mode
var targetingLine = new TargetingLine();
game.addChild(targetingLine);
game.on('down', function (obj) {
	lastTouchDownTime = Date.now(); // Capture the current timestamp when touch starts
	var pos = obj.event.getLocalPosition(game);
	// Calculate distance between click and joystick center
	var distance = Math.sqrt(Math.pow(pos.x - joystick.x, 2) + Math.pow(pos.y - joystick.y, 2));
	// If click is within joystick radius, start dragging
	if (distance <= joystick.width / 2) {
		joystickDrag = true;
	}
});
game.on('move', function (obj) {
	var pos = obj.event.getLocalPosition(game);
	if (joystickDrag) {
		var dx = pos.x - joystickBasePosition.x;
		var dy = pos.y - joystickBasePosition.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var maxDistance = joystick.width / 4; // Max distance joystick can move from center
		if (distance > maxDistance) {
			var angle = Math.atan2(dy, dx);
			dx = Math.cos(angle) * maxDistance;
			dy = Math.sin(angle) * maxDistance;
		}
		joystick.x = joystickBasePosition.x + dx;
		joystick.y = joystickBasePosition.y + dy;
		if (isThrowingMode) {
			console.log("Using joysting in throwing mode...");
			var armRotationFactor = 0.05; // Factor to control the rotation sensitivity
			var armRotation = Math.max(-Math.PI / 1.8, Math.min(Math.PI / 1.8, dx * armRotationFactor)); // Clamp rotation between -100 and 100 degrees converted to radians
			// Log armRotation in degrees
			//console.log("Arm rotation: " + (armRotation * (180 / Math.PI)).toFixed(2) + " degrees");
			player.rightArm.rotation = armRotation;
			player.leftArm.rotation = armRotation;
			// Calculate the top position of the arms and move hands to follow the arms' movement
			var rightArmTopX = player.rightArm.x + Math.cos(player.rightArm.rotation - Math.PI / 2) * (player.rightArm.height + player.rightHand.height / 1.5);
			var rightArmTopY = player.rightArm.y + Math.sin(player.rightArm.rotation - Math.PI / 2) * (player.rightArm.height + player.rightHand.height / 1.5);
			var leftArmTopX = player.leftArm.x + Math.cos(player.leftArm.rotation - Math.PI / 2) * (player.leftArm.height + player.rightHand.height / 1.5);
			var leftArmTopY = player.leftArm.y + Math.sin(player.leftArm.rotation - Math.PI / 2) * (player.leftArm.height + player.rightHand.height / 1.5);
			//console.log("rightArmTopX: " + rightArmTopX.toFixed(2) + " y " + rightArmTopY.toFixed(2));
			player.rightHand.x = rightArmTopX;
			player.rightHand.y = rightArmTopY;
			player.leftHand.x = leftArmTopX;
			player.leftHand.y = leftArmTopY;
		} else {
			console.log("Using joysting in moving mode...");
		}
	}
});
game.on('up', function (obj) {
	var touchDuration = Date.now() - lastTouchDownTime; // Calculate the duration of the touch
	isTapGesture = touchDuration <= touchTapThreshold; // Determine if the gesture is a tap based on the duration
	if (isTapGesture && player.hasBall) {
		if (isThrowingMode == 1) {
			var targetPointX = hoop.x;
			var targetPointY = hoop.y;
			ball.shootBall(targetPointX, targetPointY);
			player.hasBall = false;
		}
		isThrowingMode = 1 - isThrowingMode; // Toggle isThrowingMode between 0 and 1
		console.log("isThrowingMode: " + isThrowingMode); // Log the current joystick mode
		// Correctly toggle the joystick asset based on isThrowingMode
		if (isThrowingMode == 1) {
			joystick.attachAsset('buttonA', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			player.setPosture(throwingPosture);
			console.log("=> show targeting line"); // Log the current joystick mode
			//if (!player.isChangingPosture && player.currentPosture === "throwingPosture") 
			{
				LK.setTimeout(function () {
					//targetingLine.updateLine(ball.x, ball.y, hoop.x, hoop.y);
					targetingLine.showLine();
				}, 250);
			}
		} else {
			player.rightArm.rotation = 0;
			player.leftArm.rotation = 0;
			joystick.attachAsset('joystick', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			targetingLine.hideLine(); // Hide targeting line
		}
		joystickDrag = false;
	} else if (joystickDrag) {
		joystickDrag = false;
		joystick.x = joystickBasePosition.x;
		joystick.y = joystickBasePosition.y;
	}
});
var idle = true;
// Test postures
/* 
var changePostureTimer = LK.setInterval(function () {
	if (idle) {
		player.setPosture(runningUp1);
		idle = false;
	} else {
		player.setPosture(runningUp2);
		idle = true;
	}
}, 1000);
*/
LK.on('tick', function () {
	ball.update();
	// Check if player's trunk intersects with the ball
	if (!player.hasBall && (player.trunk.intersects(ball) || player.rightLeg.intersects(ball) || player.leftLeg.intersects(ball))) {
		ball.currentPlayer = player; // Assign the player to the ball's currentPlayer property
		player.hasBall = true; // Assign the player to the ball's currentPlayer property
	}
	// Make the ball follow the currentPlayer's position with dribble movement
	if (ball.currentPlayer && !ball.isShot) {
		ball.x = ball.currentPlayer.x;
		if (isThrowingMode == 1) {
			// Dynamically make the ball follow the player's hands position in throwing mode
			// Calculate the middle position between the two hands
			var middleHandX = (ball.currentPlayer.rightHand.x + ball.currentPlayer.leftHand.x) / 2 + ball.currentPlayer.x;
			var middleHandY = (ball.currentPlayer.rightHand.y + ball.currentPlayer.leftHand.y) / 2 + ball.currentPlayer.y;
			ball.x = middleHandX;
			ball.y = middleHandY;
			//Update the targeting line from the ball to the hoop
			//if (LK.ticks % 90 == 0)
			{
				var distanceToHoop = Math.sqrt(Math.pow(hoop.x - player.x, 2) + Math.pow(hoop.y - player.y, 2));
				// Calculate distanceImprecisionRatio based on distanceToHoop, clamped between 0.5 and 2
				var distanceImprecisionRatio = Math.min(Math.max(distanceToHoop / 600, 1), 20);
				targetPointXOffset += targetPointXOffsetDirection * targetPointXOffsetIncrement * distanceImprecisionRatio; // Increment or decrement offset by targetPointXOffsetIncrement
				if (targetPointXOffset >= targetPointXOffsetBounds || targetPointXOffset <= -targetPointXOffsetBounds) {
					targetPointXOffsetDirection *= -1; // Change direction when reaching targetPointXOffsetBounds or -targetPointXOffsetBounds
				}
			}
			var targetPointX = hoop.x + targetPointXOffset + (middleHandX - player.x),
				targetPointY = hoop.y;
			targetingLine.updateLine(ball.x, ball.y, targetPointX, targetPointY);
			// This line is removed to rely on updateLine method for visibility control
			game.addChild(ball.currentPlayer); // Ensure player is in front by re-adding it to the game
		} else if (ball.currentPlayer.isMovingUp === 0) {
			targetingLine.hideLine();
			ball.y = ball.currentPlayer.y + 150 + Math.sin(LK.ticks / (ball.currentPlayer.isMoving ? 4 : 7)) * 100;
			game.addChild(ball); // Ensure ball is in front by re-adding it to the game
		} else {
			targetingLine.hideLine();
			ball.y = ball.currentPlayer.y - 120 + Math.sin(LK.ticks / (ball.currentPlayer.isMoving ? 4 : 7)) * 50;
			game.addChild(ball.currentPlayer); // Ensure player is in front by re-adding it to the game
		}
	}
	player.updatePosture();
	player.updatePosition();
	// Re-add joystick to ensure it appears above other elements
	game.addChild(joystick);
	// Check if ball intersects with hoop and is moving downwards
	if (ball.intersects(hoop) && ball.speedY > 0) {
		score += 1;
		scoreTxt.setText(score.toString());
		//ball.reset(); //TEMP DEBUG !!!
	}
	// Reset ball if it goes off-screen
	// Check Y boundaries for the ball
	if (!ball.isFollowTrajectory)
		// when isFollowTrajectory might pass the top of screen
		{
			if (ball.y < 0 + ball.height / 2) {
				ball.y = 0 + ball.height / 2;
				ball.speedY *= -0.5; // Bounce back with reduced speed
			}
			if (ball.y > courtBottomBoundary - ball.height / 2) {
				ball.y = courtBottomBoundary - ball.height / 2;
				ball.speedY *= -0.5; // Bounce back with reduced speed
			}
		}
}); ===================================================================
--- original.js
+++ change.js
@@ -75,29 +75,25 @@
 					self.y += dy * self.followingSpeed;
 				}
 			} else if (self.isFalling) {
 				debugTxt.setText("Falling");
-				// Implement gravity and bounce mechanics with z coordinate for perspective effect
-				self.z = self.z || 0; // Initialize z if not already set
-				self.speedZ += self.gravity; // Apply gravity to z-axis speed
-				self.z += self.speedZ; // Update z position based on speed
-				// Simulate bounce effect on the court with perspective
-				var courtBounceZ = 0; // Ground level in z coordinate
-				if (self.z > courtBounceZ) {
-					self.z = courtBounceZ; // Reset z to ground level
-					self.speedZ *= -0.7; // Reverse and reduce z speed for bounce
-					// Dampen x and y speed on bounce to simulate energy loss
-					self.speedX *= 0.9;
-					self.speedY *= 0.9;
+				// Apply gravity with perspective effect
+				var fakeZ = self.y - courtBottomY; // Fake Z coordinate for 3D effect
+				self.speedY += self.gravity - fakeZ * 0.005; // Gravity decreases with "height"
+				// Move the ball
+				self.y += self.speedY;
+				// Check for ground collision in a perspective view
+				var courtBounceY = courtBottomY - (self.x - court.x) * 0.1; // Simulate perspective bounce effect
+				if (self.y > courtBounceY) {
+					self.y = courtBounceY;
+					// Reverse direction with damping for bounce effect, increase damping with each bounce
+					self.speedY *= -0.7;
 				}
-				// Update y position based on z for perspective effect
-				self.y += self.speedY + self.z * 0.05; // Adjust y movement based on z position
-				// Check if the ball has almost stopped moving
-				if (Math.abs(self.speedZ) < 0.05 && Math.abs(self.speedY) < 0.05 && self.z == courtBounceZ) {
+				// Check if the ball has almost stopped moving or is below a minimal "height"
+				if (Math.abs(self.speedY) < 0.1 || fakeZ > -10) {
 					self.isFalling = false;
 					self.isShot = false;
 					self.speedY = 0;
-					self.speedZ = 0; // Reset z speed
 				}
 			} else {
 				debugTxt.setText("wait");
 			}