How to throw a ball into a cup? - javascript

I have an image of a ball, a cup, and an inner and outer div that represent a throw power bar.
When the user clicks the ball, the power bar starts to increment and then decrements. When the user clicks the ball a 2nd time, the throw power bar stops and the ball is thrown.
As I have began coding this, I realized certain things are going to be extremely complicated, even though the idea itself is rather simple.
For example, I want the ball to be able to "bounce", meaning I will need to not only keep track of the balls x and y coordinates, but also a z coordinate representing depth.
When the ball falls to bounce, the z coordinate with be decremented, and the image of the ball should be scaled down in size, and when it begins bouncing back up, it should scale up in size, again based on the z coordinate. I also want the ball to bounce off the cup if the z coordinate is below a certain value by the time it reaches the cup, go into the cup if it is a certain sweet spot, or go over the cup if it's z value is over that sweet spot.
In the interest of keeping this somewhere short, I'll just post what I have so far. This example is lacking certain things that I was hoping people here could help me with.
http://jsfiddle.net/7Lsh78nw/
<html>
<head>
<style>
#ball {
position:absolute;
width:75px;
height:75px;
}
#cup1 {
position:absolute;
left:375px;
}
#outerPowerMeter {
position:absolute;
width:25px;
height:100px;
background-color:red;
}
#innerPowerMeter {
position:absolute;
width:25px;
height:100px;
background-color:black;
}
</style>
<script>
window.onload = function() {
var ball = document.getElementById("ball");
var yPos = 500;
var xPos = 400;
var zPos = 100;
var ballWidth = 75;
var ballHeight = 75;
var throwBallInterval;
var changeBallSizeInterval;
ball.style.top = yPos + "px";
ball.style.left = xPos + "px";
var cup1 = document.getElementById("cup1");
var powerMeter = document.getElementById("innerPowerMeter");
var powerMeterValue = 0;
var powerMeterHeight = 100;
var powerMeterActive = false;
var powerMeterInterval;
powerMeter.style.height = powerMeterHeight + "px";
ball.onclick = function() {
if (powerMeterActive == false) {
powerMeterActive = true;
startPowerMeter();
} else {
powerMeterActive = false;
stopPowerMeter();
throwBall();
}
}
function throwBall() {
throwBallInterval = setInterval(function() {
yPos = yPos - 1;
ball.style.top = yPos + "px";
}, 1);
changeBallSizeInterval = setInterval(function() {
zPos = zPos - 1;
ballWidth = ballWidth - 1;
ballHeight = ballHeight - 1;
ball.style.width = ballWidth;
ball.style.height = ballHeight;
}, 100);
}
function startPowerMeter() {
var increment = true;
powerMeterInterval = setInterval(function() {
if (increment == true) {
powerMeterValue = powerMeterValue + 1;
powerMeter.style.height = (powerMeterHeight - powerMeterValue) + "px";
if (powerMeterValue == 100) {
increment = false;
}
} else {
powerMeterValue = powerMeterValue - 1;
powerMeter.style.height = (powerMeterHeight - powerMeterValue) + "px";
if (powerMeterValue == 0) {
increment = true;
}
}
},1);
}
function stopPowerMeter() {
clearInterval(powerMeterInterval);
}
function detectCollision() { }
function detectGoal() { }
}
</script>
</head>
<body>
<img id="cup1" src="http://beerwar.com/game/images/cup.png">
<img id="ball" src="http://beerwar.com/game/images/ball.png">
<div id="outerPowerMeter">
<div id="innerPowerMeter"></div>
</div>
</body>
</html>

Since you posted such a detailed case, i thought i give you some pointers. Mind you: this is mostly vector math. I'm not a physicist either, but vector math isn't that complicated luckily! Some pythagoras here and there and you are set.
A good an fast library for that is glMatrix
A couple of things to get you going. Please note: it is pseudo code, but it does explain the concept of it.
Keep a vector for the position of the ball
Keep a vector for the position of the cup (where the ball should hit)
Keep a vector for the position of 'the camera' (since you want to scale the ball based on distance from the camera. Doesn't have to be accurate, just get the idea across)
Keep a vector for the 'direction of the force' you are going to apply to the ball. (this can be multiplied with the force from your force meter)
Keep a vector for the 'velocity of the ball'
Keep a vector for the 'gravity'
Your 'throw' function would become something along the lines of:
ball.velocity = throw.direction * throw.power
setInterval(tick,50);
Basicly, your 'tick' function (the function you apply every x-time)
ball.velocity += gravity; // we apply gravity to the speed of the ball. Pulling it down
ball.position = ball.position + ball.velocity // we add the velocity to the position every tick
if (ball.position.y < ball.radius) // if the ball is below its radius, it is colliding with the ground
{
ball.position.y = 0 - ball.position.y; // just invert its 'up' position, to make it not collide with the ground anymore
// to make the ball go back up again, invert its 'up' velocity. Gravity will get it down eventually
// dampening applied so it will bounce up less every time. For instance make that 0.9.
ball.velocity.y = 0 - (ball.velocity.y * dampening);
}
// the scale of the ball is not determined by its height, but by its distance from the camera
distanceFromCamera = (camera.position - ball.position).length()
ball.scale = 100 - (distanceFromCamera / scaleFactor);
// to make a simply guess if we are hitting the target, just check the distance to it.
distanceFromTarget = (cup.target.position - ball.position).length()
if (distanceFromTarget <= cup.target.radius) // if we 'hit the target'
handleHit()

Related

Changing Z-index Problems

I am making an old-RPG game on HTML, and I want to make a Function on Javascript
that makes the div of the player get lower than the obstacle, and when the top get higher than the obstacle, the z-index of the player go higher than the obstacle:
var top = parseInt($("#player").css("top"));
var hei = $("#player").height();
var total = top + hei;
var obTop = parseInt($("#obstacle").css("top"));
var obHei = $("#obstacle").height();
var obTotal = obHei + obTop;
if (total < obTotal) {
player.style.zIndex = 1;
$("#obstacle").css('z-index', 2);
} else {
player.style.zIndex = 2;
$("#obstacle").css('z-index', 1);
}
When top's player is higher than the obstacle (Fire)
When top is Lower
You need to compare the Y positions of the objects in question. In this case, When the fire y is lower then the player y, You want to have the player have a higher Z-index than the fire. And Vice Versa, Where when the fire y is higher than the player y, you want the fire to have a higher Z-index than the fire. You could do something like this like this:
//Define player y and fire y
player.style.zIndex = 1;
$("obstacle").css("z-index", 1);
if (playery > firey){
player.style.zIndex = 2;
} else {
$("obstacle").css("z-index", 2);
}
This hasnt been tested as there Is not a runnable example given.

How to change the direction of a sprite in a circular motion in phaserjs

I created a sprite which moves in a circular motion. I want to change the direction if the mouse button (touch) is clicked, but when the mouse is clicked, the direction does not change.
This is my code:
create: function() {
this.stage.backgroundColor = '#FFFFFF';
x = this.world.centerX;
y = this.world.centerY;
this.direction = 1;
this.speedDelta = 0.002;
this.radius = 114;
this.physics.startSystem(Phaser.Physics.ARCADE);
//adding player
this.player = this.add.sprite(x, y, 'player');
this.player.anchor.setTo(0.5, 0.5);
this.game.physics.arcade.enable(this.player);
this.input.onDown.add(this.changeDirection, this);
},
update: function() {
if (this.direction == 1) {
this.speedDelta = 0.002;
} else if (this.direction == 1) {
this.speedDelta = -0.002;
}
var period = this.time.now * this.speedDelta;
this.player.x = Math.cos(period) * this.radius;
this.player.y = d + Math.sin(period) * this.radius;
},
changeDirection: function() {
this.direction = -this.direction;
}
}
Your basic assumptions about the behavior of cos and sin are incorrect. You can't simply change the sign of the input and get a different answer.
Notice:
cos(pi/4) = 0.707
cos(-pi/4) = 0.707
sin(pi/4) = -0.707
sin(-pi/4) = -0.707
Also I think your code would benefit by using a slightly different approach in general.
Currently you're recalculating the position from scratch on every update cycle. To get the behavior you want, I think it would be simpler to instead calculate a location delta based off of the speed and direction, then simply add the delta to the current location.
That would also allow you to eliminate your conditional statement, which will make the code cleaner.

How to check if one element is in same position as another javascript

I am creating a thing that is kind of cool and basically, it's just drawing without the use of a canvas because I thought "What the hell, I'll play around with some JS". Right now my computer can handle around 4,000 different elements before becoming laggy and I can make that number larger if I could tell if there was a div under the new div I am creating, and then remove it.
How can I detect if there is already an element where the script is going to be creating a new element and remove the existing element without the use of external libraries?
<!DOCTYPE html>
<html>
<head>
<title>Drawing thing</title>
</head>
<body onmousedown="setYes()" onmouseup="setNo()">
<div id="appendThingsHere"></div>
<style>
.circle{
height:50px;
width:50px;
background:blue;
border-radius:50%;
position:absolute;
-moz-user-select:none;
-webkit-user-select:none;
user-select:none;
}
body{
overflow:hidden;
}
#appendThingsHere{
height:100%;
width:100%;
background:none;
position:absolute;
top:0;
left:0;
}
</style>
<script>
var mouseDown = "no";
var elements = 0;
function setYes(){
mouseDown = "yes";
}
function setNo(){
mouseDown = "no";
}
document.body.onmousemove = function(e){
if(mouseDown === "yes"){
if(elements < 4000){
var newCircle = document.createElement("div");
newCircle.className = "circle";
newCircle.style.top = e.clientY - 25 + 'px';
newCircle.style.left = e.clientX - 25 + 'px';
try{
var elem = document.elementFromPoint(e.clientX - 25 + 'px', e.clientY - 25 + 'px');
elem.parentElement.removeChild(elem);
elements = elements - 1;
alert("Got one!");
}
catch(err){
}
elements ++;
document.getElementById('appendThingsHere').appendChild(newCircle);
}
}
}
</script>
</body>
</html>
http://jsbin.com/hocowa/edit?html,output
Assuming this is an experiment to tinker with js... you could do this
On the handler where you draw each new div, keep track of the last one drawn
var previousCircle,
yThreshold = 10,
xThreshold = 10;
document.body.onmousemove = function(e){
if(mouseDown === "yes"){
if(elements < 4000){
var ty = Math.abs(parseInt(previousCircle.style.top, 10) - e.clientY) < yThreshold;
var tx = Math.abs(parseInt(previousCircle.style.left, 10) - e.clientX) < xThreshold;
if (ty && tx){
// if thresholds pass (new is far away enough from old) then draw a new one
var newCircle = document.createElement("div");
newCircle.className = "circle";
newCircle.style.top = e.clientY - 25 + 'px';
newCircle.style.left = e.clientX - 25 + 'px';
previousCircle = newCircle;
}
You basically decide to draw a new circle or not, based on the distance to the last circle drawn. You can tweak the "decision" with the threshold vars, the threshold condition ìf (ty || tx) or you could even calculate a vector magnitude (radius from center of each circle) to keep things geometrically correct: radius = sqrt( (newY - oldY)^2 + (newX - oldX)^2 ).
Granted, this only tracks drawings in sequence, not previous iterations. For that to work you would need to do collision checking on each draw cycle and that means iterating over all drawn divs and comparing their position to the position of the new circle. This is highly inefficient. You could speed up things a bit if you keep track of drawn circles in a index which avoids querying the DOM, only memory.
var drawnCircles = [];
for (var i in drawnCircles){
if (Math.abs(drawnCircles[i].top - e.clientY) < yThreshold && //same for x){
// draw your new circle
var newCircle = document.createElement("div");
newCircle.className = "circle";
newCircle.style.top = e.clientY - 25 + 'px';
newCircle.style.left = e.clientX - 25 + 'px';
// and keep track of it
drawnCircles.push({top: e.clientY, left: e.clientX});
}
}
The best option is to do all the logic in JavaScript and track using an array. Use the DOM only for display purposes and you should see an improvement.
You could use document.elementFromPoint(x, y);
Don't think you'd be able to handle multiple elements in a single point though. May have to iterate whilst there is an element at point to either remove or ignore.
If you want to ensure no new element with same position with the elements before, you can create Array to hold the drawn positions and draw new element only if the new position is not exist in the array. Example:
var mouseDown = "no";
var elements = 0;
var elmList = [];
function setYes() {
mouseDown = "yes";
}
function setNo() {
mouseDown = "no";
}
document.body.onmousemove = function (e) {
if ( mouseDown === "yes" ) {
if ( elements < 4000 ) {
var offset = (e.clientY - 25) + 'x' + (e.clientX - 25);
if ( elmList.indexOf(offset) < 0 ) {
var newCircle = document.createElement("div");
newCircle.className = "circle";
newCircle.style.top = e.clientY - 25 + 'px';
newCircle.style.left = e.clientX - 25 + 'px';
elements++;
elmList.push(offset);
document.getElementById('appendThingsHere').appendChild(newCircle);
}
}
}
}

Placing platforms randomly in world with Phaser

I'm making a vertical scrolling platform game using Phaser, but I can't figure out how to create randomly placed platforms to jump on. This is the code I have so far (removed unneccesary stuff):
Platformer.Game = function (game) {
this._platforms = null;
this._platform = null;
this._numberOfPlatforms = 15;
this._x = this.x;
this._y = this.y;
};
Platformer.Game.prototype = {
create: function (){
this.physics.startSystem(Phaser.Physics.ARCADE);
this.physics.arcade.gravity.y = 200;
this._platforms = this.add.group();
Platformer.platform.createPlatform(this);
Platformer.platform.createPlatform(this);
Platformer.platform.createPlatform(this);
Platformer.platform.createPlatform(this);
Platformer.platform.createPlatform(this);
Platformer.platform.createPlatform(this);
game.camera.follow(this._player);
},
managePause: function () {
this.game.paused = true;
var pausedText = this.add.text(100, 250, "Game paused. Click anywhere to continue.", this._fontStyle);
this.input.onDown.add(function(){
pausedText.destroy();
this.game.paused = false;
}, this);
},
update: function () {
}
};
Platformer.platform = {
createPlatform: function (game) {
var posX = Math.floor(Math.random() * Platformer.GAME_WIDTH * this._numberOfPlatforms * 70);
var posY = Math.floor(Math.random() * Platformer.GAME_HEIGHT * this._numberOfPlatforms * 50);
var platform = game.add.sprite(posX, posY, 'platform');
game._platforms.add(platform);
platform.events.onOutOfBounds.add(this.removePlatform, this);
},
removePlatform: function (game) {
this._platform.kill();
}
}
I can get it to work to place them randomly, but the idea of a platformer should be you could actually jump on it. With enough distance but not too much, so I guess not entirely random.
Hope you have some ideas!
Here's a simple approach, just a start really.
The idea is to build up some basic rules basing the position of each platform on the one that came before. For example, if the last one was on the left, put the next one somewhere to the right.
Min/max ranges are also good in these situations: In this example the next platform is always at least 200px higher up than the last and no more than 300px higher.
There's a playable example here on codepen
platforms = game.add.group();
platforms.enableBody = true;
platforms.physicsBodyType = Phaser.Physics.ARCADE;
// start off on the left 220px above the ground
var x = 0, y = height - 220;
// keep adding platforms until close to the top
while(y > 200) {
var platform = platforms.create(x, y, 'platform');
platform.body.immovable = true;
platform.body.allowGravity = false;
// find center of game canvas
var center = width / 2;
if(x > center) {
// if the last platform was to the right of the
// center, put the next one on the left
x = Math.random() * center;
}
else {
// if it was on the left, put the next one on the right
x = center + Math.random() * (center - platformWidth);
}
// place the next platform at least 200px higher and at most 300px higher
y = y - 200 - 100 * Math.random();
}

kineticjs :: continue animate shape from X to Y distance

I am trying to animate shape continue from from X to Y distance, again return shape from Y to X using kinetic js animate function. eg. move shape from 0px to 200px and again return shape 200px to 0px.
thanks.
You are probably looking for a Tween here rather then an Animation. Check out the kinetic documentation for more information on Tweens, however what you are looking to do will probably look something like this:
var tween = new Kinetic.Tween({
node: myShape,
x: moveToX,
y: moveToY,
duration: 1
});
Now that you have a tween, you can play it, rewind it, pause it, reverse it (again, check out the documentation for all up to date information on Tweens).
So you can now do:
tween.play()
or
tween.reverse()
to accomplish what you are looking for.
Reference: http://www.html5canvastutorials.com/kineticjs/html5-canvas-stop-and-resume-transitions-with-kineticjs/
Update (as per comment below): If you want a looping affect, in an X direction, Y direction, or both. You can do something like:
var yPos = myShape.getAttr('y'),
xPos = myShape.getAttr('x'),
maxX = 1000,
maxY = 1000,
yIncreasing = true,
xIncreasing = true; //lets assume myShape resides somewhere below the max
var anim = new Kinetic.Animation(function(frame) {
/* move the shape back and fourth in a y direction */
if (yPos < maxY && yIncreasing) {
hexagon.setY(yPos++);
} else {
if (yPos < 1) {
yIncreasing = true;
hexagon.setY(yPos++);
} else {
hexagon.setY(yPos--);
yIncreasing = false;
}
}
/* move the shape back and fourth in a x direction */
if (xPos < maxX && xIncreasing) {
hexagon.setX(xPos++);
} else {
if (xPos < 1) {
xIncreasing = true;
hexagon.setX(xPos++);
} else {
hexagon.setX(xPos--);
xIncreasing = false;
}
}
}, layer);
Note: I haven't ran this code, it should work. Using both will cause the shape to move diagonally, but hopefully this snipplet shows a solution to your problem.

Categories

Resources