Skip to content
Advertisement

Character Teleporting to side of screen when trying to move

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.

Advertisement