Circle bounce bug - javascript

I'm creating a minigame using HTML5 and jQuery without canvas (!) and, while developing the bounce part (when circle collide with stage limit), I found a bug:
When the circle collides with the bottom or right limits and you keep pressing the down/right arrow key, the circle continues bouncing with the stage limit, but when you do the same thing with the opposite stage limits (top and left), the circle bounce one or two times, and then stops (I want to get the second reaction, when it bounce and then stop). I've also discovered that this bug only occur in Safari. Can someone help me to solve it?
JSFiddle
Demo on site
<!DOCTYPE html>
<html>
<head>
<title>VelJS 3 Pre-Alpha</title>
<!-- This app was coded by Tiago Marinho -->
<!-- Special thanks to Drizr, from the interwebs -->
<!-- Do not leech it! -->
<link rel="shortcut icon" href="http://i.imgur.com/Jja8mvg.png">
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script>
var yvel = 0, xvel = 0;
var up = false, // W or arrow up
left = false, // A or arrow left
right = false, // D or arrow right
down = false; // S or arrow down
// Keydown:
document.addEventListener("keydown", function (evt) {
if (evt.keyCode == 87 || evt.keyCode == 38) { // up
up = true;
}
if (evt.keyCode == 65 || evt.keyCode == 37) { // left
left = true;
}
if (evt.keyCode == 68 || evt.keyCode == 39) { // right
right = true;
}
if (evt.keyCode == 83 || evt.keyCode == 40) { // down
down = true;
}
if (evt.keyCode == 8 || evt.keyCode == 80) { // del/p
}
});
// Keyup:
document.addEventListener("keyup", function (evt) {
if (evt.keyCode == 87 || evt.keyCode == 38) { // up
up = false;
}
if (evt.keyCode == 65 || evt.keyCode == 37) { // left
left = false;
}
if (evt.keyCode == 68 || evt.keyCode == 39) { // right
right = false;
}
if (evt.keyCode == 83 || evt.keyCode == 40) { // down
down = false;
}
});
function y(obj){
return $(obj).offset().top;
}
function x(obj){
return $(obj).offset().left;
}
setInterval(function(){
// Keydown/keyup handler:
if (up == true) {
yvel -= 2;
} else {
if (yvel < 0) {
yvel++;
}
}
if (left == true) {
xvel -= 2;
} else {
if (xvel < 0) {
xvel++;
}
}
if (right == true) {
xvel += 2;
} else {
if (xvel > 0) {
xvel--;
}
}
if (down == true) {
yvel += 2;
} else {
if (yvel > 0) {
yvel--;
}
}
var nextposx = $("circle").offset().left+xvel/16;
var nextposy = $("circle").offset().top+yvel/16;
if(nextposy < 0 || nextposy+20 > window.innerHeight){
yvel = Math.round(yvel*-0.5);
}
if(nextposx < 0 || nextposx+20 > window.innerWidth){
console.log(xvel);
xvel = Math.round(xvel*-0.5);
console.log(xvel);
}
$("circle").css({
top:$("circle").offset().top+yvel/16,
left:$("circle").offset().left+xvel/16
});
},8);
</script>
<style>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,600' rel='stylesheet' type='text/css'> * {
margin: 0;
}
html,
body {
-webkit-text-smoothing: antialiased;
height:100%;
overflow:hidden;
color: #fff;
background-color: #181818;
}
circle{
position:absolute;
top:0;
left:0;
width:20px;
height:20px;
border-radius:10px;
background:#fff;
}
</style>
</head>
<body>
<circle></circle>
</body>
</html>
I'm not using canvas because I've already tried to create this minigame using EaselJS, but I found lots of problems and there's no reason to use it in my case, since this game doesn't have any images (then there's no need for hardware acceleration).

This answer is a full update of a previous non-working answer.
The complete code of the answer is available at the bottom.
I had to check all browser to see what were the problems:
-On Chrome all were working perfectly so I had nothing to change.
-On Safari the ball was bouncing on the bottom and on the right. I figured out that the problem was caused by a position which was set in float and not in int so I just had to round the displacement.
$("circle").css({
top:Math.round($("circle").offset().top+yvel/16),
left:Math.round($("circle").offset().left+xvel/16)
});
My first answer was resolving the problem by cheating in displacements, this time the answer fix it. This amelioration shouldn't affect Chrome (but I can't test it now).
-On Firefox the ball was stopping before the bottom of the page. I just had to change comparators for collision by the body and add a margin of 0px to it.
In older versions of Firefox, when you press UP the ball was going a little DOWN before going UP, I his this bug is due to the xvel--, xvel++, yvel-- and yvel++ that are faster than xvel+=2, xvel-=2, yvel+=2 and yvel-=2 so I replace them by two times ++xvel, two times --xvel, two times ++yvel and two times --yvel which should be faster (again I can't test it right now so I hope this is working). These amelioration should't affect Chrome and Safari.
Then I optimise your code to make it more efficient.
Your HTML hasn't change.
Your css is now:
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,600' rel='stylesheet' type='text/css'> * {
margin: 0;
}
html, body {
-webkit-text-smoothing: antialiased;
height:100%;
overflow:hidden;
color: #fff;
background-color: #181818;
margin: 0px;
}
circle {
position:absolute;
top:0;
left:0;
width:20px;
height:20px;
border-radius:10px;
background:#fff;
}
Your JavaScript is now:
var yvel = 0, xvel = 0;
var up = false, // W or arrow up
left = false, // A or arrow left
right = false, // D or arrow right
down = false; // S or arrow down
// Keydown:
document.addEventListener("keydown", function (evt) {
if (evt.keyCode == 87 || evt.keyCode == 38) { // up
up = true;
}
if (evt.keyCode == 65 || evt.keyCode == 37) { // left
left = true;
}
if (evt.keyCode == 68 || evt.keyCode == 39) { // right
right = true;
}
if (evt.keyCode == 83 || evt.keyCode == 40) { // down
down = true;
}
if (evt.keyCode == 8 || evt.keyCode == 80) { // del/p
}
});
// Keyup:
document.addEventListener("keyup", function (evt) {
if (evt.keyCode == 87 || evt.keyCode == 38) { // up
up = false;
}
if (evt.keyCode == 65 || evt.keyCode == 37) { // left
left = false;
}
if (evt.keyCode == 68 || evt.keyCode == 39) { // right
right = false;
}
if (evt.keyCode == 83 || evt.keyCode == 40) { // down
down = false;
}
});
function y(obj){
return $(obj).offset().top;
}
function x(obj){
return $(obj).offset().left;
}
setInterval(function(){
// Keydown/keyup handler:
if (up) {
--yvel;
--yvel;
} else if (yvel < 0) {
yvel++;
}
if (left) {
--xvel;
--xvel;
} else if (xvel < 0) {
xvel++;
}
if (right) {
++xvel;
++xvel;
} else if (xvel > 0) {
xvel--;
}
if (down) {
++yvel;
++yvel;
} else if (yvel > 0) {
yvel--;
}
var nextposx = $("circle").offset().left+xvel/16;
var nextposy = $("circle").offset().top+yvel/16;
if(nextposy < 0 || nextposy+20 > $('body').height()){
yvel = Math.round(yvel*-0.5);
}
if(nextposx < 0 || nextposx+20 > $('body').width()){
xvel = Math.round(xvel*-0.5);
}
$('circle').css({
top:Math.round($('circle').offset().top+yvel/16),
left:Math.round($('circle').offset().left+xvel/16)
});
},8);
You have a JSFiddle of the result here.
The only error that remain is that in Firefox the circle exceeds of few pixels at the right but it's very minimal.
Sorry if my english is bad, I hope you get all what I write.
I think my job here is done...
Have fun with that =D.

Related

What's the best way to restrict movement for the camera to a certain location in THREE js?

I'm making a game that includes gravity and I need to make it so when you hit a wall or something than you can't move. I was thinking something along the lines of just stopping the forward movement but then you can just turn around and go into it backwards. No such luck so far.
Here's my movement code:
document.onkeydown = function(e) {
// e.preventDefault()
if(e.keyCode == 87) {
player.movement.w = true
}
if(e.keyCode == 65) {
player.movement.a = true
}
if(e.keyCode == 83) {
player.movement.s = true
}
if(e.keyCode == 68) {
player.movement.d = true
}
if(e.keyCode == 69) {
player.movement.e = true
}
if(e.keyCode == 81) {
player.movement.q = true
}
}
document.onkeyup = function(e) {
if(e.keyCode == 87) {
player.movement.w = false
}
if(e.keyCode == 65) {
player.movement.a = false
}
if(e.keyCode == 83) {
player.movement.s = false
}
if(e.keyCode == 68) {
player.movement.d = false
}
if(e.keyCode == 69) {
player.movement.e = false
}
if(e.keyCode == 81) {
player.movement.q = false
}
}
function loop() {
requestAnimationFrame(loop)
if(player.look.locked == true) {
if(player.movement.w == true) {
playerObj.translateZ(player.movement.speed / 100)
}
if(player.movement.a == true) {
playerObj.translateX(player.movement.speed / 100)
}
if(player.movement.s == true) {
playerObj.translateZ(player.movement.speed / 100 * -1)
}
if(player.movement.d == true) {
playerObj.translateX(player.movement.speed / 100 * -1)
}
if(player.movement.e == true) {
playerObj.translateY(player.movement.speed / 100 * -1)
}
if(player.movement.q == true) {
playerObj.translateY(player.movement.speed / 50)
}
}
}
loop()
(I know event.keyCode is depreciated)

how both player move at the same time (js game)

И have a hockey game in javascript but tво players can not move at the same time. In fact, when one moves, the other remains motionless. It is normal for both players to move at the same time in this game. Do you know a function that can help me? Should a foreign function be added? Thank you for your help.
<html>
<head>
<style>
body {
margin: 0;
}
.P1 {
position: absolute;
font-size: 110px;
background-color: white;
}
.P2 {
position: absolute;
left: 1500px;
font-size: 110px;
background-color: white;
}
</style>
</head>
<body onkeydown="keyD(event)">
<span class="P1">|</span>
<span class="P2">|</span>
</body>
<script>
var P1D = 0;
var P2D = 0;
var spanP1 = document.getElementsByClassName("P1")[0];
var spanP2 = document.getElementsByClassName("P2")[0];
function keyD(e) {
if (e.keyCode == 38 || e.keyCode == 40) {
f1(e);
}
if (e.keyCode == 83 || e.keyCode == 87) {
f2(e);
}
}
function f1(e) {
if (e.keyCode == 40) {
if (P2D >= 620) {
} else {
P2D += 10;
spanP2.style.top = P2D + "px";
}
}
if (e.keyCode == 38) {
if (P2D <= -20) {
} else {
P2D -= 10;
spanP2.style.top = P2D + "px";
}
}
}
function f2(e) {
if (e.keyCode == 83) {
if (P1D >= 620) {
} else {
P1D += 10;
spanP1.style.top = P1D + "px";
}
}
if (e.keyCode == 87) {
if (P1D <= -20) {
} else {
P1D -= 10;
spanP1.style.top = P1D + "px";
}
}
}
</script>
</html>
You would need to remember which keys are pressed down or not. For example by saving their state in an object.
Furthermore, when player 1 has a key pressed and player 2 starts pressing another, the key of player 1 stops repeating for a moment. To prevent this you would need to stop relying on the key repeat of the system of the user. For example by using a setInterval or later implement it into your gameloop. Example:
// Save key states in an object
const keystates = {}
document.addEventListener('keydown', e => {
keystates[e.code] = true
})
document.addEventListener('keyup', e => {
keystates[e.code] = false
})
// Repeat the key action in your gameloop
const repeat_interval = 500
setInterval(() => {
if (keystates['KeyW']) console.log('Player1 up')
if (keystates['KeyS']) console.log('Player1 down')
if (keystates['ArrowUp']) console.log('Player2 up')
if (keystates['ArrowDown']) console.log('Player2 down')
}, repeat_interval)
EDIT:
Also don't use keyCode as it is deprecated

Trouble with adding gravity to 2d platformer

I am trying to make a 2D platforming game and I am missing an essential part of it, gravity.
I have tried everything from look at questions on this website to looking at online tutorials and you-tube videos.
I really need help with getting gravity into this game as I am out of ideas.
As I said I have already tried looking at multiple tutorials and videos, including this one:
http://www.somethinghitme.com/2013/01/09/creating-a-canvas-platformer-tutorial-part-one/
but this one uses shapes created in canvas rather than images.
I already know that you have to use a velocity function as well as variable for the gravity. Then you have to put this all inside the key handler function so that it can get executed.
//spaceman variables
var sx = canvasWidth / 2; // start the spaceman in the centre
var sy = canvasHeight / 2;
var sdx = 0; // set initial speed to 0
var sdy = 0;
var sspeed = 3; // create a variable for speed
var gravity = 0.2;
var svX = 0;
var svY = (Math.random() * -10) - 5;
//set variables to use for key presses
//these are Boolean variables
//they can only be true or false
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
spaceman2Ready = true;
spacemanReady = false;
leftPressed = true;
} else if (e.keyCode == 38) {
upPressed = true;
} else if (e.keyCode == 40) {
downPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
sdx--;
} else if (e.keyCode == 37) {
spaceman2Ready = false;
spacemanReady = true;
leftPressed = false;
sdx--;
} else if (e.keyCode == 38) {
upPressed = false;
sdx--;
} else if (e.keyCode == 40) {
downPressed = false;
sdx--;
}
}
// add something to "listen" for an event
//an event is keypress, mouse movement, mouse click etc.
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (rightPressed == true) {
sdx = sspeed;
} else if (leftPressed == true) {
sdx = -sspeed;
} else if (upPressed == true) {
sdy = -sspeed;
} else if (downPressed == true) {
sdy = sspeed
}
if (rightPressed == false && leftPressed == false && upPressed == false && downPressed == false) {
sdx = 0;
sdy = 0;
}
sx = sx + sdx;
sy = sy + sdy;
}
if (spacemanReady) {
ctx.drawImage(spacemanImage, sx, sy);
if (spaceman2Ready) {
ctx.drawImage(spaceman2Image, sx, sy);
}
// basically the setTimeout part, but this time its requesting the function that we made at the top
requestAnimationFrame(draw);
}
// this is to get the loop for the animation to start going
window.addEventListener("load",
function() {
draw();
});
< /script>
</body >
</html>/
You should be using gravity to update your position every frame (in the draw function). This would look like:
if(sy > 0){
sdy += gravity
}
I have created a codepen with your game with gravity. I hope this helps!

Tetris on Java Script key control problem

I am having a problem when I move my key controls mainly the arrows on the keyboard. If the viewpoint is small enough it also moves the screen up and down because of the vertical side bar and the tetris piece at the same time. And I want the pieces to only move when I press the arrows. I am a novice at Js and I am not sure where to start to solve the problem, suggestions to where to start to look at?
Here is my Js script
document.addEventListener("keydown", CONTROL);
function CONTROL(event) {
if (event.keyCode == 37) {
p.moveLeft();
dropStart = Date.now();
}
else if (event.keyCode == 38) {
p.rotate();
}
else if (event.keyCode == 39) {
p.moveRight();
dropStart = Date.now();
}
else if (event.keyCode == 40) {
p.moveDown(0);
}
}
Arrow keys moving the browser window is a default browser behavior.
Use event.preventDefault()
To listen only to arrow keys use if (k >= 37 && k <= 40) {, or the opposite: if (k < 37 || k > 40) return;
const p = { // JUST FOR THIS DEMO. You use Piece.prototype
moveLeft() { console.log("LEFT"); },
rotate() { console.log("ROTATE"); },
moveRight() { console.log("RIGHT"); },
moveDown() { console.log("DOWN"); },
};
document.addEventListener("keydown", CONTROL);
function CONTROL(event) {
const k = event.keyCode;
if (k < 37 || k > 40) return; // Do nothing if was not an arrow key. Else Do:
event.preventDefault(); // Prevent browser scroll on arrows
if(k == 37 || k == 39) dropStart = Date.now(); // Only for left or right
return {
37: p.moveLeft,
38: p.rotate,
39: p.moveRight,
40: p.moveDown
}[k]();
}
html, body {min-height: 100%;}
so the problem here is that is that it's sensing each key individually (I've had the same problem so you need a keymap to keep track off ALL the keys pressed like so:
var keys = [];
function keysPressed(e) {
keys[e.keyCode] = true;
}
function keysReleased(e) {
keys[e.keyCode] = false;
}
if(keys[37] === true){
//do stuff here
}
if(keys[38] === true){
//do stuff here
}
You may also want to use the proper identifier "==="

How to write a good Caps Lock detection solution in JavaScript?

Found this Caps Lock detection solution. Fiddle here: https://jsfiddle.net/07ugkacn/11/ (Thank you Armfoot). JS/jQuery code here:
$(function () {
var isShiftPressed = false;
var isCapsOn = null;
$("#txtName").bind("keydown", function (e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode == 16) {
isShiftPressed = true;
}
});
$("#txtName").bind("keyup", function (e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode == 16) {
isShiftPressed = false;
}
if (keyCode == 20) {
if (isCapsOn == true) {
isCapsOn = false;
$("#error").hide();
} else if (isCapsOn == false) {
isCapsOn = true;
$("#error").show();
}
}
});
$("#txtName").bind("keypress", function (e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode >= 65 && keyCode <= 90 && !isShiftPressed) {
isCapsOn = true;
$("#error").show();
} else {
$("#error").hide();
}
});
});
Works perfectly for my needs. I'm trying to rewrite it in JavaScript though, with no jQuery. How do I rewrite the bind methods without the jQuery? I've tried storing the input fields in a variable and writing
passwordInput.onkeyup = function(e) { ... }
... For example. But to no avail. Think this is what's stopping this solution from working.
Help pls thx.
EDIT: Figured it out on my own
For whom it may concern, a solution for caps detection in vanilla JavaScript. The problem with most of the solutions floating around on the internet is they only show/hide an alert/popup when the user starts typing in the input field. This is not optimal because the "Caps Lock is on" notification is still visible after the user has turned Caps Lock off, and remains so until they resume typing. This is long and unwieldy, and I still don't quite understand it myself. But I recommend it all the same.
function capsDetect() {
var body = document.getElementsByTagName('body')[0];
var isShiftPressed = false;
var isCapsOn = null;
var capsWarning = document.getElementById('caps-lock-warning');
body.addEventListener('keydown', function(e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode = 16){
isShiftPressed = true;
}
});
body.addEventListener('keyup', function(e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if(keyCode == 16) {
isShiftPressed = false;
}
if(keyCode == 20) {
if(isCapsOn == true) {
isCapsOn = false;
capsWarning.style.visibility = 'hidden';
} else if (isCapsOn == false) {
isCapsOn = true;
capsWarning.style.visibility = 'visible';
}
}
});
body.addEventListener('keypress', function(e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if(keyCode >= 65 && keyCode <= 90 && !isShiftPressed) {
isCapsOn = true;
capsWarning.style.visibility = 'visible';
} else {
capsWarning.style.visibility = 'hidden';
}
});
}
shiftCaps();
Gaweyne, nicely done! I tested your pure JS code and there are some things that I modified which you may find interesting:
ignored control characters while typing (<= 40), such as directional and removal keys;
replaced if (keyCode = 16){ to if (keyCode === 16){ and other == in the same way;
used display property instead of visibility (CSS);
considered isCapsOn as a boolean, always;
called capsDetected instead of shiftCaps.
You can run the snippet below to check it out:
function capsDetect() {
var body = document.getElementsByTagName('body')[0];
var isShiftPressed = false;
var isCapsOn = false;
var capsWarning = document.getElementById('error');
body.addEventListener('keydown', function(e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode === 16) {
isShiftPressed = true;
}
});
body.addEventListener('keyup', function(e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode === 16) {
isShiftPressed = false;
}
if (keyCode === 20) {
if (isCapsOn) {
isCapsOn = false;
capsWarning.style.display = 'none';
} else {
isCapsOn = true;
capsWarning.style.display = 'inline-block';
}
}
});
body.addEventListener('keypress', function(e) {
var keyCode = e.keyCode ? e.keyCode : e.which;
if (keyCode <= 40)
return;
if (keyCode >= 65 && keyCode <= 90 && !isShiftPressed) {
isCapsOn = true;
capsWarning.style.display = 'inline-block';
} else {
capsWarning.style.display = 'none';
}
});
}
capsDetect();
body {
font-family: Arial;
font-size: 10pt;
}
#error {
border: 1px solid #FFFF66;
background-color: #FFFFCC;
display: inline-block;
margin-left: 10px;
padding: 3px;
display: none;
}
<form action="">
<input id="txtName" type="text" /><span id="error">Caps Lock is ON.</span>
</form>
Maybe some more tweaking will make it perfect... There is still the CAPS LOCK detection on page load: maybe by simulating user input in the background will let us know, but right now I haven't completely figured it out yet.
Btw, I never thought of doing this before, but it is clear that it helps users, specially in passwords fields. In fact, I may personally use it! So I really appreciate your time for posting this up :)

Categories

Resources