How to update line while pressing "Shift" key? - javascript

I am trying to draw straight line with pressing key "Shift".After pressing "Shift" i want to set cursor on line at 45/90 degree angle. While drawing a line on Mouse_Move event.
Diagrammatically i want like this.
For that i have written code as below:
if (isShiftKeyPressed) {
endX = evt.X;
endY = evt.Y;
var deltaX = endX -startX;
var deltaY = endY - startY;
var angleInRadian = Math.atan2(deltaY, deltaX);
var angleInDegree = angleInRadian * 180 / Math.PI;//error in this line
if (deltaX > 0 && deltaY > 0) {
if (angleInDegree > 45 && angleInDegree < 90) {
UpdateLastPosition(endX,startY);
}
if (angleInDegree < 45 && angleInDegree > 0) {
UpdateLastPosition(startX,endY);
}
}

I think you're asking how to tell if the shift key is down.
evt.shiftKey will be true if the shift key was down when the event was generated, false if it wasn't.
So your
![if (isShiftKeyPressed) {
would be
if (evt.shiftKey) {
// The shift key was down when the event was generated
}
else {
// It wasn't
}
(I assume the ! before if was a typo.)
Example (source)

Related

Matter.js Apply Force Onto Body Using Angle and Power Level

I am currently trying to apply force to a body using a degree (a float between -90 and 90), and a forceLevel (a float between 0 and 1). Body.applyForce() only allows me to provide x and y power levels.
What I am trying to achieve:
I want to be able to drag back from a position, and have my body launch towards the other directions with the power of the launch based on how much the user dragged back.
Here is my code for getting the angle and the power level.
var cachedPosition = {
x: 0,
y: 0
};
document.addEventListener("mousedown", (e) => {
cachedPosition.x = e.clientX
cachedPosition.y = e.clientY
})
document.addEventListener("mouseup", (e) => {
var degree = "INVALID";
var difX = cachedPosition.x - e.clientX
var difY = cachedPosition.y - e.clientY
if (difX > 0 && difY < 0) {
var degree = getDegree(difX, difY)
} if (difX < 0 && difY < 0) {
var degree = -getDegree(Math.abs(difX), difY); // Negative degree if drag is towards bottom right.
}
var power = Math.sqrt(Math.pow(difX, 2)+Math.pow(difY, 2))/1000
})

Js collision detector - hit the wall vs. hit the floor (difference)

I'm making a small game with one player and blocks that builds up the environment. The problem I'm having is knowing the difference between when the player hits the ground (the top of a block), and hitting a wall (the side of the block).
So far the player can walk on the ground just fine, but when he meets a wall, he immediately jumps to the top of that block.
This is my collision detector:
function collisionDetector(){
if(myPlayer.y + myPlayer.h > c.height){ //Bottom of the canvas
myPlayer.vy = 0;
myPlayer.ay = 0;
myPlayer.y = c.height - myPlayer.h;
myPlayer.onGround = true;
console.log(myPlayer.y + myPlayer.h, c.height);
}
if(myPlayer.x + myPlayer.w >= c.width){ //right side of canvas
myPlayer.x = c.width - myPlayer.w;
myPlayer.vx = 0;
}
if(myPlayer.x <= 0){ //Left side of canvas
myPlayer.x = 0;
myPlayer.vx = 0;
}
function hitTest(a,b){ //hitTest between two objects
if(a.y + a.h > b.y && a.y < b.y + b.h && a.x + a.w > b.x && a.x < b.x + b.w){
return true;
}
}
for(var i = 0; i < blocks.length; i++){ //Loop through blocks
if(hitTest(myPlayer, blocks[i])){ //If it touches a block
myPlayer.y = blocks[i].y - myPlayer.h;
myPlayer.onGround = true; //onGround = ready to jump
}
}
}
I realized that I'm setting the players y pos to be on top of what ever block it hits, but I cannot figure out a solution to this problem. Can anyone help me or at least lead me in the right direction? Thanks!
(Let me know if you need more of the code)
PS: the player is just a head. No body hiding behind the blocks.
So basically, what you need to do is to check collision between many points in the player.
In the snippet you can show many points represented in the player.
Bottom almost-left and almost-right (in blue), check against below blocks. They are not fully left or right, in order to prevent a race condition which will allow the player to climb walls. In that case, if the player is pushing against a wall and jumping, the collider will detect both side collision and bottom collision as true, then the player will quickly move to the top until there are no more blocks.
Left and right points (in black), check against edges of the blocks. This is just a point instead of two like the bottom edge, because we don't need more for this particular case. One more for each side could be easily added to get a better detection.
Top point (in red) checks against the top blocks. This is in the middle in order to allow the player a more easy way to tranverse the map. If this is not needed, you would need to add one more point like in the bottom edge (but never reaching the far edge, because that will generate a race condition).
So in summary, to have a good collision detection based on points (instead of raycasts), you need to detect the player like if it where a rounded shape, in order to prevent strange behaviours.
You can player around with the map layout by altering the layout variable. 0's are empty space, 1's are brown blocks and 2's are green blocks.
The collisionDetector fuction has comments to understand what's going on.
Also I have added a jump feature since I understand you would need that as well.
const c = document.getElementById('canvas');
c.width = window.innerWidth;
c.height = window.innerHeight;
const ctx = c.getContext('2d');
// map layout
const layout =
`000000001
001000001
000000101
100110111
222222222`;
// convert layout to blocks
const blocks = [...layout].reduce((a, c, i) => {
if (i === 0 || c === "\n") a.push([]);
if (c === "\n") return a;
const y = a.length - 1;
const row = a[y];
const x = row.length;
row.push({x: x * 32, y: y * 32, t:c, w:32, h:32});
return a;
}, []).reduce((a, c) => a.concat(c), []);
// player starting position
const myPlayer = {x: 32*1.5, y: 0, h: 32, w: 16, onGround: true};
const gravity = -1;
let pkl = 0, pkr = 0;
let pvely = 0;
function render() {
// player logic
const pvelx = pkr + pkl;
const speed = 2;
myPlayer.x += pvelx * speed;
myPlayer.y -= pvely;
if (pvely > -2) pvely += gravity;
const debugColliders = collisionDetector();
ctx.clearRect(0, 0, c.width, c.height);
// player render
ctx.fillStyle = '#FFD9B3';
ctx.fillRect(myPlayer.x, myPlayer.y, myPlayer.w, myPlayer.h);
renderLayout();
debugColliders();
window.requestAnimationFrame(render);
}
function renderLayout() {
const colors = {'1': '#A3825F', '2': '#7FAC72'}
blocks.forEach(b => {
if (+b.t > 0) {
ctx.fillStyle = colors[b.t];
ctx.fillRect(b.x, b.y, b.w, b.h);
}
});
}
window.addEventListener('keydown', e => {
if (e.key == 'ArrowRight') {
pkr = 1;
e.preventDefault();
} else if (e.key == 'ArrowLeft') {
pkl = -1;
e.preventDefault();
} else if (e.key == 'ArrowUp') {
if (myPlayer.onGround)
pvely = 8;
myPlayer.onGround = false;
e.preventDefault();
}
});
window.addEventListener('keyup', e => {
if (e.key == 'ArrowRight') {
pkr = 0;
} else if (e.key == 'ArrowLeft') {
pkl = 0;
}
});
function collisionDetector(){
const p = myPlayer;
const playerTop = p.y;
const playerLeft = p.x;
const playerRight = playerLeft + p.w;
const playerBottom = playerTop + p.h;
const playerHalfLeft = playerLeft + p.w * .25;
const playerHalfRight = playerLeft + p.w * .75;
const playerHMiddle = playerLeft + p.w * .5;
const playerVMiddle = playerTop + p.h * .5;
if(playerBottom > c.height){ //Bottom of the canvas
p.vy = 0;
p.ay = 0;
p.y = c.height - p.h;
p.onGround = true;
}
if(playerRight >= c.width){ //right side of canvas
p.x = c.width - p.w;
p.vx = 0;
}
if(playerLeft <= 0){ //Left side of canvas
p.x = 0;
p.vx = 0;
}
blocks.forEach(b => { //Loop through blocks
if (b.t === "0") return; // If not collidable, do nothing
const blockTop = b.y;
const blockLeft = b.x;
const blockRight = blockLeft + b.w;
const blockBottom = b.y + b.h;
// Player bottom against block top
if ((playerBottom > blockTop && playerBottom < blockBottom) && // If player bottom is going through block top but is above block bottom.
((playerHalfLeft > blockLeft && playerHalfLeft < blockRight) || // If player left is inside block horizontal bounds
(playerHalfRight > blockLeft && playerHalfRight < blockRight))) { // Or if player right is inside block horizontal bounds
p.y = blockTop - p.h;
p.onGround = true;
}
// Player top against block bottom
if ((playerTop < blockBottom && playerTop > blockTop) && // If player top is going through block bottom but is below block top.
((playerHMiddle > blockLeft && playerHMiddle < blockRight))) { // If player hmiddle is inside block horizontal bounds
p.y = blockBottom;
p.onGround = false;
}
// Player right against block left, or player left against block right
if (playerVMiddle > blockTop && playerVMiddle < blockBottom) { // If player vertical-middle is inside block vertical bounds
if ((playerRight > blockLeft && playerRight < blockRight)) { // If player vmiddle-right goes through block-left
p.x = blockLeft - p.w;
} else if ((playerLeft < blockRight && playerRight > blockLeft)) { // If player vmiddle-left goes through block-right
p.x = blockRight;
}
}
});
return function debug() {
ctx.fillStyle = 'black';
ctx.fillRect(playerLeft, playerVMiddle, 1, 1);
ctx.fillRect(playerRight, playerVMiddle, 1, 1);
ctx.fillStyle = 'red';
ctx.fillRect(playerHMiddle, playerTop, 1, 1);
ctx.fillStyle = 'blue';
ctx.fillRect(playerHalfLeft, playerBottom, 1, 1);
ctx.fillRect(playerHalfRight, playerBottom, 1, 1);
}
}
window.requestAnimationFrame(render);
html, body{ width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; }
canvas { background: #7AC9F9; display: block; }
<canvas id="canvas"></canvas>
Introduce a block[i].type attribute. For instance if block[i].type=='floor' then make player stay on floor. If for another instance block[i].type=='wall' then make it stop moving through the wall. When block[i].type=='brick' or square or block or whatever, them it's a mixture of two.
Another part to be edited is when you check the collisions. What if you have only one-direction collision? What I am saying is maybe use or instead of and in this part if(a.y + a.h > b.y && a.y < b.y + b.h && a.x + a.w > b.x && a.x < b.x + b.w){
Also you could check each collision separately, like
function hitTest(a,b){ //hitTest between two objects
var collisions = {up: false, down: false, left: false, right: false};
collisions.up = (a.y + a.h > b.y ) || collisions.up
collisions.down = (a.y < b.y + b.h ) ||collisions.down
collisions.right = ( a.x + a.w > b.x) || collisions.right
collisions.left = (a.x < b.x + b.w) || collisions.left
return collisions
}
var escapeFrom = {
down: function(player, block){
player.y = block.y + block.h;
player.onGround = true; //onGround = ready to jump
},
up: function(player, block){
// you logic to escape from hitting the ceiling
},
// and for the next 2
left: function(player, block) {},
right: function(player, block){}
}
// Now here you check whether your player hits blocks
for(var i = 0; i < blocks.length; i++){ //Loop through blocks
cls = hitTest(myPlayer, blocks[i]) //If it touches a block
Object.keys(cls).map(function(direction, ind){
if (cls[direction]){
// call escape from function to escape collision
escapeFrom[direction](myPlayer, blocks[i]);
}
})
}
This is highly unoptimized, the whole your code is unoptimized, but at least it can help to move further.

FabricJS - disable panning viewport -x -y axis

if the mouse goes out of canvas and mouse move in -x -y axis , I want disable pan.
how can i disable viewpoint -x -y axis.
this is my code.
var panning = false;
canvas.on('mouse:up', function (e) {
if (isPaningMode) {
panning = false;
}
});
canvas.on('mouse:out', function (e) {
if (isPaningMode) {
panning = false;
}
});
canvas.on('mouse:down', function (e) {
if (isPaningMode) {
panning = true;
}
});
canvas.on('mouse:move', function (e) {
canvas.selection = !isPaningMode;
if (isPaningMode && e && e.e && panning) {
var units = 10;
var delta = new fabric.Point(e.e.movementX, e.e.movementY);
canvas.relativePan(delta);
}
});
Thank you, sorry i cant speak english well. :(
Edit
my canvas is size : 800x800
I just want to use the red striped area. I do not want to use sections with X. I do not want them to be shown by scrolling in these fields. I did what I said for the objects. But I could not do it for panning. In short, I want to panning only in the direction of the arrow.
Make sure you're using the latest version of FabricJS, they are continually improving it. I noticed in the past that canvas.on('mouse:out') was targeting objects and not the canvas.
Here's a working JSFiddle, https://jsfiddle.net/rekrah/bvgLvd3u/.
I'm assuming this was the issue because you were already disabling panning on mouse-out of the canvas.
canvas.on('mouse:out', function(e) {
if (isPaningMode) {
panning = false;
}
});
Let me know if I miss understood your English - which is very good, by-the-way!
After Your Edit
Bulk of the change is in the mouse-move event. In summary: Keeping track of the distance moved so we know where we started from, to get back to (with a tweak, if needed) - hope that makes sense???
var deltaX = 0;
var deltaY = 0;
canvas.on('mouse:move', function(e) {
if (isPaningMode && e && e.e && panning) {
moveX = e.e.movementX;
if (deltaX >= 0) {
deltaX -= moveX;
if (deltaX < 0) {
moveX = deltaX + moveX;
deltaX = 0;
}
}
moveY = e.e.movementY;
if (deltaY >= 0) {
deltaY -= moveY;
if (deltaY < 0) {
moveY = deltaY + moveY;
deltaY = 0;
}
}
if (deltaX >= 0 && deltaY >= 0) {
canvas.relativePan(new fabric.Point(moveX, moveY));
}
}
});
Here's a new, updated, and working :) JSFiddle, https://jsfiddle.net/rekrah/r3gm3uh9/.

How to submit click via x and y orientation?

I have a remote control pen as cursor (hardware).
External hardware via SDK to Javascript i receive a cursor.
Where i get x, x, y, y position and click command.
But, How to submit click on that position?
(no matter whatever Element is there on that position, i need to submit the click on that position)
if (_label == rs.cursor.GestureType.CURSOR_CLICK) {
// I have: x, x, y, y
/*
Following method works:
but i have too many buttons, how to apply dynamic click without tracking which element?
var myButton = document.getElementById("mediaplayer");
var rect = myButton.getBoundingClientRect();
if (x >= rect.left &&
x <= rect.right &&
y >= rect.top &&
y <= rect.bottom){
myButton.click();
}
*/
}
EDIT:
//
// 1 - Find Active DIV/MAP/Container?
//
var layerID = $('#layoutmain').attr('usemap');
if (_label == rs.cursor.GestureType.CURSOR_CLICK) {
//
// 2 - Loop each buttons of that container
//
$('#' + layerID).find('area').each(function(){
var onclick_function = $(this).attr('onclick') ;
var coords = $(this).attr('coords');
coords = coords.split(' ').join('');
var coords_array = coords.split(',');
console.log('>>> we have: ',
onclick_function ,
coords,
coords_array);
var rectleft = coords_array[0];
var recttop = coords_array[1];
var rectright = coords_array[2];
var rectbottom = coords_array[3];
//
// 3 - Match the RANGE of buttons with the coordinates
//
if (x >= rectleft && y >= recttop &&
x <= rectright && y <= rectbottom){
$(this).trigger('click');
}
});
}
Method 1: When the CURSOR_CLICK event is triggered, iterate all the clickable buttons and check to which button the click is "related" to.
$buttons = $('.clickable-button');
var rect;
if (_label == rs.cursor.GestureType.CURSOR_CLICK) {
$buttons.each(function(){
rect = $(this).getBoundingClientRect();
if (x >= rect.left &&
x <= rect.right &&
y >= rect.top &&
y <= rect.bottom){
$(this).click();
}
});
}
Method 2: Create an array with all the buttons on the page and their cords.
When the click event is being triggered, just compare the cords.
Advantage - Less time is being spent in the loop.

Getting a gun to fire

I'm trying to make a top down shooter game to learn about coding in HTML/JS/CSS.
I've got a canvas, my player moves and rotates on the canvas, but I'm having some trouble getting his gun working. I've got this with the aid of tutorials and searching through other stackoverflow posts, but this one I can't seem to fix alone.
I have defined a variable 'gunfire' which is set to 1 if the left mouse button is pressed and is otherwise 0, in my function draw() I have an if statement that should draw a rectangle in front of my sprite (to represent bullets) when the left mouse button is pressed.
The problem I have is that the bullets appear at all times, independent of whether the mouse button is pressed. If anyone can point out what it is that I'm doing wrong then I would be very grateful, here's the code (the canvass is created in separate HTML/CSS files):
var turn = 0;
var frameRate = 24;
var main_x = 0,
main_y = 0,
move_x = 0,
move_y = 0;
var gunfire = 0;
var speed = 4;
function keyPress(e) {
if (e.keyCode == 68) { //d
move_x = speed;
}
if (e.keyCode == 65) { //a
move_x = -speed;
}
if (e.keyCode == 83) { //s
move_y = speed;
}
if (e.keyCode == 87) { //w
move_y = -speed;
}
if (e.keyCode == 1) { //left mouse
gunfire = 1;
}
}
function keyRelease(e) {
if (e.keyCode == 68) { //d
move_x = 0;
}
if (e.keyCode == 65) { //a
move_x = 0;
}
if (e.keyCode == 83) { //s
move_y = 0;
}
if (e.keyCode == 87) { //w
move_y = 0;
}
if (e.keyCode == 1) { //left mouse
gunfire = 0;
}
}
function move() {
main_x += move_x;
main_y += move_y;
if (main_x < -220) {
main_x = -220
}
if (main_y < -220) {
main_y = -220
}
if (main_x > 220) {
main_x = 220
}
if (main_y > 220) {
main_y = 220
}
}
function mouseMove(e) {
var mouseX, mouseY;
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
} else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
mouseX = mouseX - (top_canvas.width / 2) - main_x;
mouseY = mouseY - (top_canvas.height / 2) - main_y;
window.radians = Math.atan2(mouseY, mouseX);
//document.getElementById("info").innerHTML = radians
}
var background = new Image();
background.src = "assets/background3.jpg";
var player1 = new Image();
player1.src = "assets/player1.png";
function draw() { //draws all content on the canvas
ctx_1.save();
ctx_1.clearRect(0, 0, top_canvas.width, top_canvas.height);
ctx_1.drawImage(background, 0, 0);
ctx_1.translate(top_canvas.width / 2 + main_x, top_canvas.height / 2 + main_y);
ctx_1.rotate(turn);
ctx_1.drawImage(player1, -25, -25, 50, 70);
if (gunfire = 1) {
ctx_1.fillStyle = "#000";
ctx_1.fillRect(0, -10, 200, 20);
}
ctx_1.restore();
}
function gameLoop() {
// all functions to update go here
draw();
turn = window.radians
move();
}
function init() {
window.top_canvas = document.getElementById("top_canvas");
window.ctx_1 = top_canvas.getContext("2d");
setInterval(gameLoop, 1000 / frameRate);
//event fires every time the mouse moves
top_canvas.addEventListener("mousemove", mouseMove, false);
window.addEventListener("keydown", keyPress, false);
window.addEventListener("keyup", keyRelease, false);
}
window.addEventListener("load", init, false);
First of all, as Kippie points out, you're setting gunfire to 1 each time which results in a true statement. It must be changed to == or === (latter preferable) or simply drop the comparison as the non-zero value would be true:
if (gunfire) {
...
}
Second, you are checking for mouse clicks inside a key handler and assuming keyCode would indicate a mouse button click. keyCode 1 is not related to mouse clicks at all and no mouse clicks will end up here.
Third, you are not having any event handler for mouse clicks...
To solve these issues (in addition to the first) add an event handler for mouse clicks:
top_canvas.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mouseup", mouseUp, false);
Then inside the handlers (only showing for mouse down):
function mouseDown(e) {
if (e.button === 0) { // check left mouse-button
gunfire = 1;
}
}
The reason for using window for mouse up is that in case your mouse pointer is outside the canvas element the up event won't register and the gun will continue to fire. Using the window object will allow you to register up event even in this situation.
if (gunfire = 1)
You're using the assignment operator, rather than doing a comparison.
Use === instead.

Categories

Resources