Why does it only work as expected the second time?

Asked

Viewed 77 times

2

I have that function:

for (var i in chars) {
        chars[i].walk();
        for (var j in chars) {
            if (i != j) {
                collision(chars[i], chars[j]);
                action(chars[i], chars[j]);
            }
        }
    }

Does it work in an unexpected way when I call for the first time, only when I call it for the second time in a row does it work? (it doesn’t work if I call her and then another and then call her again).

chars is an array guarding class ojets Character.

collision works properly and I tried to take it out and did not change at all.

Function walk:

walk () {
    if (!this.acting && this.walking) {
        switch (this.walking) {
            case "left":
                this.animate(9, 9);
                this.posX -= this.speed;
                break;
            case "right":
                this.animate(11, 9);
                this.posX += this.speed;
                break;
            case "up":
                this.animate(8, 9);
                this.posY -= this.speed;
                break;
            case "down":
                this.animate(10, 9);
                this.posY += this.speed;
                break;
        }
    }
}

The complete files are these:

  1. index.html:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Undivine</title>
    <link href="css/style.css" rel="stylesheet">
</head>
<body>
    <div>
        <canvas height="600" id="canvas" width="800"></canvas>
    </div>
    <script src="js/load.js" onload="loadJS('js/message', 'js/character', 'js/collision', 'js/script')"></script>
</body>
</html>
  1. css/styles.css:
@import "https://fonts.googleapis.com/css?family=Alfa+Slab+One";
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
body {
    text-align: center;
}
#canvas {
    background-color: #f00;
    cursor: pointer;
    margin-top: 10px;
}
  1. js/character.js:
class Character {
    constructor (img, posX, posY, visible) {
        //propriedades
        this.acting = null;
        this.height = 64;
        this.img = img;
        this.posX = posX;
        this.posY = posY;
        this.speed = 3;
        this.srcX = 0;
        this.srcY = 10;
        this.step = 0;
        this.visible = visible;
        this.walking = null;
        this.width = 64;
    }
    //metodos
    action () {
        if (this.acting) {
            switch (this.acting) {
                case "spellcast":
                    var cols = 7;
                    var srcY = 0 + this.srcY % 4;
                    break;
                case "thrust":
                    var cols = 8;
                    var srcY = 4 + this.srcY % 4;                   
                    break;
                case "slash":
                    var cols = 6;
                    var srcY = 12 + this.srcY % 4;                  
                    break;
                case "shoot":
                    var cols = 13;
                    var srcY = 16 + this.srcY % 4;                  
                    break;
                case "hurt":
                    var cols = 6;
                    var srcY = 20;                  
                    break;
            }
            if (this.animate(srcY, cols)) {
                var acting = this.acting;
                this.acting = null;
                this.step = 0;
                if (acting != "hurt") {
                    this.srcX = 0;
                }
                return acting;
            }
        }
    }
    animate (srcY, cols) {
        if (this.srcY == srcY) {
            this.srcX = Math.floor(this.step / 5) % cols;
            this.step++;
            return this.step == cols * 5 - 1;
        } else {
            this.srcY = srcY;
            this.step = 0;
        }
    }
    bottomEdge () {
        return this.posY + this.height;
    }
    centerX () {
        return this.posX + this.width / 2;
    }
    centerY () {
        return this.posY + this.height / 2;
    }
    cursor (e) {
        return e.offsetX >= this.posX && e.offsetX < this.rightEdge() && e.offsetY >= this.posY && e.offsetY < this.bottomEdge()?true:false;
    }
    direction () {
        switch (this.srcY % 4) {
            case 0:
                return "up";
                break;
            case 1:
                return "left";
                break;
            case 2:
                return "down";
                break;
            case 3:
                return "right";
                break;
        }
    }
    draw (cnv, ctx) {
        if (this.visible) { 
            switch (this.posX) {
                case "center":
                    this.posX = (cnv.width - this.width) / 2;
                    break;
                case "left":
                    this.posX = 0;
                    break;
                case "right":
                    this.posX = cnv.width - this.width;
                    break;
            }
            switch (this.posY) {
                case "middle":
                    this.posY = (cnv.height - this.height) / 2;
                    break;
                case "top":
                    this.posY = 0;
                    break;
                case "bottom":
                    this.posY = cnv.height - this.height;
                    break;
            }
            ctx.drawImage(this.img, this.srcX * this.width, this.srcY * this.height, this.width, this.height, this.posX, this.posY, this.width, this.height);
        }
    }
    halfHeight () {
        return this.height / 2;
    }
    halfWidth () {
        return this.width / 2;
    }
    rightEdge () {
        return this.posX + this.width;
    }
    stop (direction) {
        if (this.walking == direction) {
            this.walking = null;
        }
    }
    walk () {
        if (!this.acting && this.walking) {
            switch (this.walking) {
                case "left":
                    this.animate(9, 9);
                    this.posX -= this.speed;
                    break;
                case "right":
                    this.animate(11, 9);
                    this.posX += this.speed;
                    break;
                case "up":
                    this.animate(8, 9);
                    this.posY -= this.speed;
                    break;
                case "down":
                    this.animate(10, 9);
                    this.posY += this.speed;
                    break;
            }
        }
    }
}
  1. js/collision.js:
function action (a, b) {
    switch (a.action()) {
        case "shoot":
            shoot(a, b);
            break;
        case "thrust":
        case "slash":
            attack(a, b);
            break;
    }
}
function collision (a, b) {
    var x = Math.abs(a.centerX() - b.centerX());
    var y = Math.abs(a.centerY() - b.centerY());
    var width = a.halfWidth() + b.halfWidth();
    var height = a.halfHeight() + b.halfHeight();
    if (x < width && y < height && b.visible) {
        switch (a.direction()) {
            case "up":
                a.posY += height - y;
                break;
            case "left":
                a.posX += width - x;
                break;
            case "down":
                a.posY -= height - y;
                break;
            case "right":
                a.posX -= width - x;
                break;
        }
    }
}
function shoot (a, b) {
    switch (a.direction()) {
        case "up":
            if (a.centerX() > b.posX && a.centerX() < b.rightEdge() && a.posY > b.posY) {
                b.visible = false;
            }
            break;
        case "left":
            if (a.centerY() > b.posY && a.centerY() < b.bottomEdge() && a.posX > b.posX) {
                b.visible = false;
            }
            break;
        case "down":
            if (a.centerX() > b.posX && a.centerX() < b.rightEdge() && a.posY < b.posY) {
                b.visible = false;
            }
            break;
        case "right":
            if (a.centerY() > b.posY && a.centerY() < b.bottomEdge() && a.posX < b.posX) {
                b.visible = false;
            }
            break;
    }
}
function attack (c, d) {
    var x = Math.abs(c.centerX() - d.centerX());
    alert(x);
    var y = Math.abs(c.centerY() - d.centerY());
    var width = c.halfWidth() + d.halfWidth();
    var height = c.halfHeight() + d.halfHeight();
    switch (c.direction()) {
        case "up":
            if (x <= width && y <= height && c.posY > d.posY) {
                d.visible = false;
            }
            break;
        case "left":
            if (x <= width && y <= height && c.posX > d.posX) {
                d.visible = false;
            }
            break;
        case "down":
            if (x <= width && y <= height && c.posY < d.posY) {
                d.visible = false;
            }
            break;
        case "right":
            if (x <= width && y <= height && c.posX < d.posX) {
                d.visible = false;
            }
            break;
    }
}
  1. js/load.js:
//carrega javascript
function loadJS () {
    for (var i in arguments) {
        document.write("<script src='" + arguments[i] + ".js'></script>");
    }
}
//carrega imagens
function loadImgs () {
    var imgs = new Object();
    for (var i in arguments) {
        var start = arguments[i].lastIndexOf("/") + 1;
        var end = arguments[i].indexOf(".");
        var name = arguments[i].substring(start, end);
        imgs[name] = new Image();
        imgs[name].src = arguments[i];
    }
    return imgs;
}
  1. js/message.js:
class Message {
    constructor (text, x, y, font, color, visible) {
        //propriedades
        this.text = text;
        this.x = x;
        this.y = y;
        this.font = font;
        this.color = color;
        this.visible = visible;
    }
    //metodos
    fillText (cnv, ctx) {
        if (this.visible) { 
            ctx.font = this.font;
            switch (this.x) {
                case "center":
                    this.x = (cnv.width - ctx.measureText(this.text).width) / 2;
                    break;
                case "left":
                    this.x = 0;
                    break;
                case "right":
                    this.x = cnv.width - ctx.measureText(this.text).width;
                    break;
            }
            switch (this.y) {
                case "middle":
                    this.y = (cnv.height - parseInt(this.font)) / 2;
                    break;
                case "top":
                    this.y = 0;
                    break;
                case "bottom":
                    this.y = cnv.height - parseInt(this.font);
                    break;
            }
            ctx.fillStyle = this.color;
            ctx.fillText(this.text, this.x, this.y, cnv.width);
        }
    }
}
  1. js/script.js:
//carrega as imagens
var imgs = loadImgs("img/character/princess.png", "img/character/skeleton.png", "img/character/soldier.png");
//onload
onload = function () {
    //variaveis
    var cnv = document.getElementById("canvas");
    var ctx = cnv.getContext("2d");
    ctx.textBaseline = "top";
    var msgs = [];
    var chars = [];
    var status = "start";
    //cria as mensagens
    msgs["title"] = new Message("UNDIVINE", "center", "middle", "80px 'Alfa Slab One'", "#fff", true);
    //cria os personagens
    chars["player"] = new Character(imgs["princess"], "left", "middle", false);
    chars["skeleton"] = new Character(imgs["skeleton"], "center", "middle", false);
    chars["soldier"] = new Character(imgs["soldier"], "right", "middle", false);
    //eventos
    cnv.addEventListener("click", function () {
        if (status == "start") {
            msgs["title"].visible = false;
            for (var i in chars) {
                chars[i].visible = true;
            }
            status = "play";
        }
    }, false);
    addEventListener("keydown", function (e) {
        if (status == "play") {
            switch (e.keyCode) {
                case 37:
                    chars["player"].walking = "left";
                    break;
                case 38:
                    chars["player"].walking = "up";
                    break;
                case 39:
                    chars["player"].walking = "right";
                    break;
                case 40:
                    chars["player"].walking = "down";
                    break;
            }
        }
    }, false);
    addEventListener("keyup", function (e) {
        if (status == "play") {
            switch (e.keyCode) {
                case 37:
                    chars["player"].stop("left");
                    break;
                case 38:
                    chars["player"].stop("up");
                    break;
                case 39:
                    chars["player"].stop("right");
                    break;
                case 40:
                    chars["player"].stop("down");
                    break;
                case 88:
                    chars["player"].acting = "slash";
                    break;
            }
        }
    }, false);
    //funcoes
    function loop () {
        requestAnimationFrame(loop);
        if (status == "play") {
            update();
        }
        render();
    }
    function update () {
        for (var i in chars) {
            chars[i].walk();
            for (var j in chars) {
                if (i != j) {
                    collision(chars[i], chars[j]);
                    action(chars[i], chars[j]);
                }
            }
        }
    }
    function render () {
        //limpa o canvas
        ctx.clearRect(0, 0, cnv.width, cnv.height);
        //desenha os personagens
        for (var i in chars) {
            chars[i].draw(cnv, ctx);
        }
        //escreve as mensagens
        for (var i in msgs) {
            msgs[i].fillText(cnv, ctx);
        }
    }
    //inicia as funcoes
    loop();
}
  1. img/character/princess.png:

princess.png

  1. img/character/skeleton.png:

skeleton.png

  1. img/character/soldier.png:

soldier.png

Or, if you want to download everything from Google Drive, the URL is https://drive.google.com/drive/folders/0B7nZsfA3eMi9NHpjQ3FIRTlybFk?usp=sharing

  • 4

    What it is and how it is declared chars? What are the functions collision and action? Where and how the method is declared walk?

  • I will edit the question.

  • If you want I can upload the files to google drive, it is very light, still is right at the beginning.

  • Explain better what the "unexpected way" is. And what is the first time? By the code you put on the drive, this is inside an infinite loop, with requestAnimationFrame.

  • The unexpected is that when press x it attacks with the Lat and when it ends should detect if it hit the target but the first time it detects how it did not hit, and the second it detects that it hit.

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.