I’m very new to HTML, CSS, and JavaScript. My darthVader character keeps on teleporting to the side of the screen any time I try to do any movement. I think this might be a problem with my CSS. Also I am open to any and all suggestions for changes for this project. Whether it is efficiency, layout, or any math involved in this project. Right now I’m just learning as I go instead of watching a hand holding tutorial.
//Global variables let deathStar = document.querySelector(".deathStar") let counter = 0; let darthVader = document.querySelector(".darthVader"); let vaderX = window.scrollX + darthVader.getBoundingClientRect().left; const x1 = window.scrollX + deathStar.getBoundingClientRect().left; // top left X const y1 = window.scrollY + deathStar.getBoundingClientRect().top; // top left Y const x2 = window.scrollY + deathStar.getBoundingClientRect().right; // bottom right X const y2 = window.scrollY + deathStar.getBoundingClientRect().bottom; // top right Y //Create a storm trooper function createStormTrooper(){ colorArray = ['blue', 'green', 'orange', 'yellow', 'white', 'red','purple', 'pink']; counter++; //create each div let stormTrooper = document.createElement('div'); let body = document.createElement('div'); let gun = document.createElement('div'); let head = document.createElement('div'); let legSplit = document.createElement('div'); //append div to proper div deathStar.append(stormTrooper); stormTrooper.append(body); body.append(gun); body.append(head); body.append(legSplit); //add classes stormTrooper.classList.add("trooper",'stormTrooperPart' + counter, "stormTrooper"); body.classList.add("trooper", 'stormTrooperPart' + counter, "body"); gun.classList.add("trooper", 'stormTrooperPart' + counter, "gun"); head.classList.add("trooper", 'stormTrooperPart' + counter, 'head'); legSplit.classList.add("trooper", 'stormTrooperPart' + counter, "legSplit"); let randomColor = Math.floor(Math.random()*8); body.style.backgroundColor = colorArray[randomColor]; placeInsideDeathStar(stormTrooper); } //Places a trooper in a random spot inside the death star function placeInsideDeathStar(stormTrooper){ let midPointX = (x2 + x1) / 2; let midPointY = (y2 + y1) / 2; let radius = x2 - midPointX - 10; let theta = Math.random() * Math.PI * 2; let r = (Math.sqrt(Math.random()) * radius); let yRandom = r * Math.sin(theta); let xRandom = r * Math.cos(theta); stormTrooper.style.transform = "translate(" + (xRandom) + "px," + (yRandom) + "px)"; } //Create Troopers for(let i = 0; i < 10;i++ ){ createStormTrooper(); } //Storm Trooper Removal document.addEventListener('click', (e) => { //variable to check if type stormtrooper let typeTrooper = e.target.className.split(" ")[0]; if(typeTrooper == "trooper"){ let stormTrooperChecker = document.querySelector("." + e.target.className.split(" ")[1]); stormTrooperChecker.remove(); } alert(e.x); console.log("Y: " + e.y); }); //Character Movement document.addEventListener("keydown", function(e) { if(e.key =='d'){ vaderX += 2; darthVader.style.left = vaderX + "px"; } if(e.key =='a'){ vaderX -= 2; darthVader.style.left = vaderX + "px"; } });
body{ border: 0; background: black; display: flex; align-items: center; justify-content: center; } .deathStar { position: relative; display:flex; height: 700px; width: 700px; border-radius: 50%; background-color: darkgrey; top: 50%; align-items: center; justify-content: center; } .hole{ display: flex; height: 100px; width: 50px; border-radius: 50%; background-color: gray; top: 50%; transform: translateX(-60PX); } .stormTrooper{ display: flex; position: absolute; z-index: 2; } .body{ display: flex; position: relative; height: 30px; width: 10px; z-index: 2; } .head{ display: flex; position: relative; height: 7px; width: 9px; transform: translate(-5px, 1px); background-color: black; } .gun{ position: relative; display: flex; height: 2px; width: 10px; background-color: black; transform: translate(-5px, 10px) } .legSplit{ position: relative; display: flex; width: 1px; height: 8px; background-color: black; transform: translate(-5px, 22px); } .darthVader{ display: flex; position: absolute; height: 30px; width: 10px; z-index: 3; background-color: black; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="style.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> </head> <body> <div class="deathStar" id="deathStar"> <div class="darthVader"></div> </div> <div class="hole"></div> <script src="main.js"></script> </body> </html>
Advertisement
Answer
Because the initial values of vaderX
aren’t the same as the X coordinate (or style.left
) of the darthVader
initial position.
getBoundingClientRect
returns the position relative to the viewport. The darthVader
element is inside an element with position: relative
. The value darthVader.style.left
is relative to the parent with a position
that is not static
.
https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
The Element.getBoundingClientRect() method returns a DOMRect object providing information about the size of an element and its position relative to the viewport. (…) Properties other than width and height are relative to the top-left of the viewport.
https://developer.mozilla.org/en-US/docs/Web/CSS/position
absolute (…) It is positioned relative to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block. Its final position is determined by the values of top, right, bottom, and left.
https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block
The size and position of an element are often impacted by its containing block. Most often, the containing block is the content area of an element’s nearest block-level ancestor, but this is not always the case. (…) The process for identifying the containing block depends entirely on the value of the element’s position property (…)
You fix the issue if you replace:
let vaderX = window.scrollX + darthVader.getBoundingClientRect().left;
with:
let vaderX = darthVader.offsetLeft;
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft
The HTMLElement.offsetLeft read-only property returns the number of pixels that the upper left corner of the current element is offset to the left within the HTMLElement.offsetParent node.