Instructions on incorporating a logical condition for an object that is entering a region in motion

I am currently in the process of developing a new game concept. The goal of the game is to maneuver a square across the screen while avoiding raindrops that fall from the top of the canvas. I need assistance with programming the logic so that when a raindrop intersects with the square, it resets back to the starting position at x = 0. Below is the current code snippet:

var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');

var WIDTH = 1000;
var HEIGHT = 700;
var x = 0;
var y = HEIGHT-20;
var xPos = [0];
var yPos = [0];
var speed = [1];
var rainDrops = 50;
var rectWidth = 20;
var rectHeight = 20;

for (var i = 0; i < rainDrops; i++) {
    xPos.push(Math.random() * WIDTH);
    yPos.push(0);
    speed.push(Math.random() * 5);
}

function rainFall () {

    window.requestAnimationFrame(rainFall);
    ctx.clearRect(0, 0, WIDTH, HEIGHT);

    for (var i = 0; i < rainDrops; i++) {
        //Rain
        ctx.beginPath();
        ctx.arc(xPos[i], yPos[i], 3, 0, 2 * Math.PI);
        ctx.fillStyle = 'blue';
        ctx.fill();

        //Rain movement
        yPos[i] += speed[i];

        //Square
        ctx.fillStyle = 'red';
        ctx.fillRect(x, y, rectWidth, rectWidth);

        if (yPos[i] > HEIGHT) {
            yPos[i] = 0;
            yPos[i] += speed[0];
        }

        //Logic to reset square position
        if (/*condition*/) {
            x = 0;
        }
    }
};

//Move square object

function move(e) {
    if (e.keyCode === 37) {
        ctx.clearRect(0, 0, WIDTH, HEIGHT);
        x -= 10;
    }
    if (e.keyCode === 39) {
        ctx.clearRect(0, 0, WIDTH, HEIGHT);
        x += 10;
    }
    canvas.width = canvas.width;
}

//Lock arrow key events

window.addEventListener("keydown", function(e) {
    if ([37, 39].indexOf(e.keyCode) > -1) {
        e.preventDefault();
    }
}, false);

rainFall(); 
document.onkeydown = move;
window.addEventListener("load", doFirst, false);

Answer №1

Conditions and Decisions

I find myself in a bit of a dilemma when it comes to answering these types of questions. As you're just starting out, I want to avoid overwhelming you with complex code and techniques, yet at the same time, I don't want to promote any incorrect practices.

The Simple Answer

First off, let's address your code snippet:

//This is the part where I need the Help!!!!!!!!!
// the test checks the center of the drop 
// if drop is greater than > top of player (y) and (&&) 
// drop x  greater than > left side of player x and (&&) drop is less than <
// right side of player (x + rectWidth) then drop has hit player   
if (yPos[i] > y && xPos[i] > x && xPos[i] < x + rectWidth ){
    x = 0; // move player back
}

By the way, you're drawing the player's rectangle for each raindrop. It would be better to move that draw function outside the loop.

The Detailed Answer

I hope my explanation isn't too confusing, and I've included ample comments to clarify my decisions.

To maintain organization, I segment different elements into separate objects - the player, rain, and keyboard handler. These components are coordinated through the mainLoop, which is triggered once per frame using requestAnimationFrame and executes necessary functions.

The player object encompasses all player-related data and functions for drawing and updating the player's position.

The rain object contains an array called rain.drops to store raindrops along with functions for drawing, updating, randomizing drops, and adding new ones.

In determining if rain hits the player, I handle this check within the rain.update function while moving the raindrops. Since I'm unsure of the desired outcome upon impact, I simply reset the raindrop and increment a hit counter.

Initially, I inspect whether the raindrop's bottom (drop.y + drop.radius) surpasses the player's top (player.y), thus omitting unnecessary evaluations for rain above the player.

Next, I evaluate the rain horizontally. Assessing for non-collision scenarios simplifies logic. If the drop's right is left of the player's left or its left is right of the player's right, I determine the drop doesn't contact the player by putting the condition inside parentheses and preceding it with a negation operator if(! ( ... ) ).

Given the complexity of the test, I break it into two lines for clarity.

// drop is a single rain drop player is the player
 if (drop.y + drop.radius >= player.y) {
     if (! (drop.x + drop.radius < player.x || 
     drop.x - drop.radius > player.x + player.width)) { 
         // code for player hit by rain in here
     }
 }

Furthermore, the rain.update function also checks if raindrops touch the canvas' bottom and resets them accordingly.

Live Demonstration

I've tweaked and incorporated your provided code into a functional setup.

addEventListener("load",function(){  
    var canvas = document.getElementById('gameCanvas');
    var ctx = canvas.getContext('2d');
    ctx.font = "20px arial";
    var frameCount = 0;

    var WIDTH = canvas.width;
    var HEIGHT = canvas.height;    
    var currentMaxDrops = 5;
    const numberFramesPerRainIncrease = 60 * 5;
    const maxRainDrops = 150;  
    
    addEventListener("keydown", keyEvent);
    addEventListener("keyup", keyEvent);    
    requestAnimationFrame(mainLoop);

    const keys = {  
        ArrowLeft : false,
        ArrowRight : false,
    }
    function keyEvent(event){  
        if(keys[event.code] !== undefined){
            event.preventDefault();  
            keys[event.code] = event.type === "keydown";  
        }
    }


    const player = {  
        x : 0,          
        y : HEIGHT - 20,  
        width : 20,      
        height : 20,      
        speed : 4,       
        color : "red",
        showHit : 0,  
        hitCount : 0,   
        status(){  
            if(player.hitCount === 0){
                return "Dry as a bone.";
            }
            if(player.hitCount < 5){
                return "A little damp.";
            }
            if(player.hitCount < 15){
                return "Starting to get wet.";
            }
            return "Soaked to the core";
        },
        draw(){  
           if(player.showHit > 0){
               player.showHit -= 1; 
               ctx.fillStyle = "blue";
           }else{
               ctx.fillStyle = player.color;
           }
           ctx.fillRect(player.x,player.y,player.width,player.height);
        },
        update(){ 
           if(keys.ArrowLeft){
               player.x -= player.speed;  
               keys.ArrowLeft = false; 
               if(player.x < 0){ 
                    player.x = 0; 
               }
           }
           if(keys.ArrowRight){
               player.x += player.speed;  
               keys.ArrowRight = false; 
               if(player.x + player.width >= WIDTH){ 
                    player.x = WIDTH - player.width; 
               }
           }
        }
            
    }

    const rain = {  
        numberRainDrops : 50,
        drops : [],  
        randomizeDrop(drop){ 
            drop.x = Math.random() * WIDTH;  
            drop.y = -10;                      
            drop.radius = Math.random() *3 + 1; 
            drop.speed = Math.random() * 4 + 1; 
            return drop;
        },
        createDrop(){  
            if(rain.drops.length < currentMaxDrops){
                rain.drops.push(rain.randomizeDrop({}));
                rain.numberRainDrops = rain.drops.length;
            }
        },
        draw(){    
            ctx.beginPath();  
            ctx.fillStyle = 'blue';  
            for(var i = 0; i < rain.drops.length; i ++){
                var drop = rain.drops[i]; 
                ctx.arc(drop.x, drop.y, drop.radius, 0, 2 * Math.PI);
                ctx.closePath(); 
            }        
            ctx.fill();    
        },
        update(){
            for(var i = 0; i < rain.drops.length; i ++){
                var drop = rain.drops[i]; 
                drop.y += drop.speed;     
                if(drop.y + drop.radius >= player.y){ 
                     if(!(drop.x + drop.radius < player.x || 
                        drop.x - drop.radius > player.x + player.width)){ 
                        player.hitCount += 1;
                        player.showHit += 5;
                        rain.randomizeDrop(drop); 
                     }
                }
                if(drop.y > HEIGHT + drop.radius){ 
                      rain.randomizeDrop(drop); 
                }
            }        
        }
    }
            
    function mainLoop () {  
        requestAnimationFrame(mainLoop);  
        ctx.clearRect(0, 0, WIDTH, HEIGHT);
        frameCount += 1; 
        if(frameCount % numberFramesPerRainIncrease === 0){
            if(currentMaxDrops < maxRainDrops){
               currentMaxDrops += 1;
            }
        }
        
        rain.createDrop(); 
        rain.update();  
        player.update();   
        player.draw();   
        rain.draw();  
        ctx.fillStyle = "black";
        ctx.fillText("Hit " + player.hitCount + " times.",5,20);
        ctx.setTransform(0.75,0,0,0.75,5,34); 
        ctx.fillText(player.status(),0,0); 
        ctx.setTransform(1,0,0,1,0,0); 
    };

});
canvas {
   border : 2px black solid;
}
<canvas id="gameCanvas" width=512 height=200></canvas>

I trust this information proves valuable to you.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Struggling to pass a function argument as a string for use within the function

Although the title may seem unclear, I will clarify. I have a collection of images on the left side and I have implemented an onclick function on each one to display the image and some information on the right side. It's like having thumbnails on the ...

Unable to begin the previous project on my Mac, but it functions properly on Windows

After running npm i, I encountered the following error message which I am unsure how to resolve. I tried reinstalling Node.js, Python, and Pyenv, but the issue persists. Interestingly, the same version of Node.js on Windows runs the project without any p ...

Steps for regularly executing 'npm run build' on the server

My website doesn't require frequent content updates, as users don't always need the latest information. As a result, most pages are generated server-side and served as static pages. There will be occasional database updates that need to be visib ...

Swap Text Inside String - JS

I have a challenge where I need to extract an ID from an HTML element and then replace part of the extracted word. For instance: HTML <input type="checkbox" id="facebookCheckbox"></div> JavaScript var x = document.getElementById("facebookCh ...

Exploring VueJs 3's Composition API with Jest: Testing the emission of input component events

I need help testing the event emitting functionality of a VueJs 3 input component. Below is my current code: TextInput <template> <input v-model="input" /> </template> <script> import { watch } from '@vue/composition-api&ap ...

Implement a new list field to an object using javascript

I am facing a challenge in converting a JSON object to a list of JSON objects and then adding it back to JSON. Here is an example: config = { existing_value: 'sample' } addToListing = (field, value, index=0) => { config = { ...confi ...

What is the method for retrieving array values from an attribute?

I am currently developing an Angular 6 application and I need to pass and retrieve array values dynamically through attributes. Here is the code snippet I have used for this purpose: HTML: <ul class="list-unstyled" id="list" [attr.parent_id]="123"> ...

What is the best way to combine the average hours, minutes, seconds, and milliseconds in JavaScript?

I am seeking guidance on how to calculate the average of three different times in JavaScript. In the scenario presented below, the average of the three times is calculated as 01:42:22:566. <form action="/action_page.php"> <label for= ...

Transform your standard HTML buttons into a collective of radio buttons

Looking for a way to make some ordinary buttons function as radio buttons without adding another library to the project. Any suggestions on how this can be achieved using just HTML and JavaScript/jQuery? Appreciate any help, thank you. ...

"JavaScript: Issue Encountered While Converting Hexadecimal to Decimal

I've been working on a custom function to convert hexadecimal to decimal in my Scratch project: function Hex2Decimal(hex){ var deci = 0; var num = 1; var hexstr = String(hex); hexstr = hexstr.toLowerCase(); var expon = 0; for( ...

Unable to alter Mui input label color upon focus using theme.ts

In my next.js app, I'm facing an issue with changing the color of the label in a Material UI input field using Mui. Despite updating the theme.ts file to change the border bottom color and label color, only the border bottom color is being applied. T ...

tsconfig.json: No input files were detected in the configuration file

I am encountering an issue with my tsconfig.ts file where it says "No inputs were found in config file 'd:/self-study/Web/Learning/Express/tsconfig.json'. Specified 'include' paths were '["**/*"]' and 'exclude&a ...

Deliver a message using a loop in jade

I'm struggling with posting a request in Node and Jade using a specific ID. For instance, if Node returns a list of books : res.render('tests', {books: books}); In my Jade template, I display all the books by iterating through them. b ...

Issue with submitting forms in modal using Bootstrap

In the model box below, I am using it for login. When I click on either button, the page just reloads itself. Upon checking in Firebug, I found something like this: localhost\index.php?submit=Login <div class="modal fade" id="loginModal" tabindex= ...

The visual symbol is not being shown on the selection box in Mozilla Firefox

I've encountered an issue with a checkbox I created to display a + and - for expand and collapse functionality. HTML Code: <input type=checkbox class="ins" ng-model=show ng-class='{open:show}'><b>Show</b> CSS code: .ins ...

Tips for modifying CSS when a user scrolls beyond a specific div

Currently, I am working on implementing a scroll function that dynamically moves elements based on the user's scrolling behavior. The code I have written works to some extent and successfully moves the elements. However, my goal is to create a list o ...

The click function for the parent div will not be executed if I click on the child div

Hey, I encountered an issue in my code that I need help with. $(document).ready(function() { $(document).on('click', '.rohit', function() { alert('rohit'); }) $(document).on('click', '.azad', ...

Trigger a random tune when hovering the mouse

I need help figuring out how to make a fixed image on my page trigger a random sound track when hovered over. The sound could be one of five different tracks. Here is the HTML for my image: <img src="images/Airplane.png" class="Airplane-photo"> Bel ...

Conceal a div and label after a delay of 5 seconds with a JavaScript/jQuery function in C#

Here is a sample div: <div class="alert alert-success alert-dismissable" runat="server" visible="false" id="lblmsgid"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ...

`Finding it difficult to halt the spread of events in reactJs`

One of my conditions involves a simple dropdown menu: handleDropdown = (e) => { if (e.type === "focus") { console.log("inside dropdown focus"); this.setState({ dropDownDis: "block" }) } else if (e.type === "blur") { console.lo ...