HTML5画布|弹跳球|循环通过图像阵列并在每个球上放置不同的背景图像,居中

问题描述 投票:1回答:1

我有点噩梦将不同的背景图像应用到在重力和画布的边界下在画布上反弹的球上,最终在底部沉降并堆叠。

我创建了一个图像数组,我试图循环并为每个图像创建一个球,其中图像成为一个居中的背景。

我可以使图像居中,但这会使球看起来离开画布的边界。所以已经恢复了这种变化。

我无法让背景图像与之前的球不同。所有球上显示的图像是阵列中的最后一个图像。但是,创建的球数确实反映了阵列中的图像数量。

这是一个指向codepen的链接:https://codepen.io/jason-is-my-name/pen/BbNRXB

html, body{
    width:100%;
    height:100%;
    margin: 0;
    padding: 0;
    background: #333333;
}
*{
    margin: 0;
    padding: 0;
}
    .container {
        width: 410px;
        height: 540px;
    }
    #ball-stage{
        width: 100%;
        height: 100%;
    }

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="container">
    <canvas id="ball-stage" ></canvas>
</div>

<script>
    /*
    /*
     * Created by frontside.com.au
     * Amended by Jason
    */

    $(document).ready(function () {
        $.ajaxSetup({
            cache: true
        });
        var url1 = "https://code.createjs.com/easeljs-0.6.0.min.js";
        $.getScript(url1, function () {
            new App();
        })
    });

    function App() {

        var self = this;
        self.running = false;
        self.initialized = false;
        var stageClicked = false;
        var stage, canvas;

        var canvasWidth = 410;
        var canvasHeight = 540;
        var bounce = -0.75;
        var balls = [];
        var _gravityY = 1;
        var _gravityX = 0;
        var FPS = 30;
        var infoText, detailsText;
        var ballsInitalized = false;
        var iOS = navigator.userAgent.match(/(iPod|iPhone|iPad)/);

        self.initialize = function () {
            toggleListeners(true);
            self.initCanvas();
            self.initGame();
        };

        var toggleListeners = function (enable) {
            if (!enable) return;
        };

        self.refresh = function () {}

        self.initCanvas = function () {
            canvas = $("#ball-stage").get(0);
            stage = new createjs.Stage(canvas);

            window.addEventListener('resize', onStageResize, false);
            onStageResize();
            createjs.Touch.enable(stage);
            createjs.Ticker.addListener(tick);
            createjs.Ticker.setFPS(FPS);

            self.initialized = true;
        }

        self.initGame = function () {
            initBalls(canvasWidth, canvasHeight);
        }

        var onStageResize = function () {
            stage.canvas.width = canvasWidth;
            stage.canvas.height = canvasHeight;
        }

        var initBalls = function (stageX, stageY) {

            var imagesArray = ["img-1.png","img-2.png","img-3.png","img-4.png","img-5.png","img-6.png","img-7.png","img-8.png"];

            for (var i = 0; i < imagesArray.length; i++) {
                console.log(i);

                var imageArray = imagesArray[i];
                console.log(imageArray);

                setTimeout(function () {

                    var arrayImage = new Image();
                    console.log(arrayImage);

                    arrayImage.onload = function(){

                        addBall(arrayImage, stageX / 2, 0);

                    }

                    arrayImage.src = imageArray;

                }, i * 1000);

            }
        }

        var addBall = function (img, x, y) {
            console.log(img);
            var shape = new createjs.Shape();
            shape.id = balls.length;
            shape.radius = 51.25;
            shape.mass = shape.radius;
            shape.x = x;
            shape.y = y;
            shape.vx = rand(-3, 3);
            shape.vy = rand(-3, 3);

            var image = new Image();
            image.src = img;
            shape.graphics.beginBitmapFill(img,'repeat').drawCircle(0, 0, shape.radius);

            stage.addChild(shape);
            balls.push(shape);
        }

        var numBalls = function () {
            return balls.length;
        }
        var tick = function () {
            balls.forEach(move);
            for (var ballA, i = 0, len = numBalls() - 1; i < len; i++) {
                ballA = balls[i];
                for (var ballB, j = i + 1; j < numBalls(); j++) {
                    ballB = balls[j];
                    checkCollision(ballA, ballB);
                }
            }

            stage.update();
        }

        var rotate = function (x, y, sin, cos, reverse) {
            return {
                x: (reverse) ? (x * cos + y * sin) : (x * cos - y * sin),
                y: (reverse) ? (y * cos - x * sin) : (y * cos + x * sin)
            };
        }

        var checkCollision = function (ball0, ball1) {
            var dx = ball1.x - ball0.x,
                dy = ball1.y - ball0.y,
                dist = Math.sqrt(dx * dx + dy * dy);
            //collision handling code here
            if (dist < ball0.radius + ball1.radius) {
                //calculate angle, sine, and cosine
                var angle = Math.atan2(dy, dx),
                    sin = Math.sin(angle),
                    cos = Math.cos(angle),
                    //rotate ball0's position
                    pos0 = {
                        x: 0,
                        y: 0
                    }, //point
                    //rotate ball1's position
                    pos1 = rotate(dx, dy, sin, cos, true),
                    //rotate ball0's velocity
                    vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true),
                    //rotate ball1's velocity
                    vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true),
                    //collision reaction
                    vxTotal = vel0.x - vel1.x;
                vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) /
                    (ball0.mass + ball1.mass);
                vel1.x = vxTotal + vel0.x;
                //update position - to avoid objects becoming stuck together
                var absV = Math.abs(vel0.x) + Math.abs(vel1.x),
                    overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
                pos0.x += vel0.x / absV * overlap;
                pos1.x += vel1.x / absV * overlap;
                //rotate positions back
                var pos0F = rotate(pos0.x, pos0.y, sin, cos, false),
                    pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
                //adjust positions to actual screen positions
                // ball1.x = ball0.x + pos1F.x;
                setBallX(ball1, ball0.x + pos1F.x)
                //ball1.y = ball0.y + pos1F.y;
                setBallY(ball1, ball0.y + pos1F.y)
                // ball0.x = ball0.x + pos0F.x;
                setBallX(ball0, ball0.x + pos0F.x)
                // ball0.y = ball0.y + pos0F.y;
                setBallY(ball0, ball0.y + pos0F.y)
                //rotate velocities back
                var vel0F = rotate(vel0.x, vel0.y, sin, cos, false),
                    vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
                ball0.vx = vel0F.x;
                ball0.vy = vel0F.y;
                ball1.vx = vel1F.x;
                ball1.vy = vel1F.y;
            }
        }

        var checkWalls = function (ball) {
            if (ball.x + ball.radius > canvas.width) {
                //  ball.x = canvas.width - ball.radius;
                setBallX(ball, canvas.width - ball.radius)
                ball.vx *= bounce;
            } else
            if (ball.x - ball.radius < 0) {
                // ball.x = ball.radius;
                setBallX(ball, ball.radius)
                ball.vx *= bounce;
            }
            if (ball.y + ball.radius > canvas.height) {
                //  ball.y = canvas.height - ball.radius;
                setBallY(ball, canvas.height - ball.radius)
                ball.vy *= bounce;
            } else
            if (ball.y - ball.radius < 0) {
                //ball.y = ball.radius;
                setBallY(ball, ball.radius)
                ball.vy *= bounce;
            }
        }

        var move = function (ball) {
            ball.vy += _gravityY;
            ball.vx += _gravityX;
            setBallX(ball, ball.x + ball.vx)
            setBallY(ball, ball.y + ball.vy)
            checkWalls(ball);
        }
        var setBallX = function (ball, x) {
            if (isNaN(ball.pointerID)) {
                ball.x = x
            }
        }
        var setBallY = function (ball, y) {
            if (isNaN(ball.pointerID)) {
                ball.y = y
            }
        }

        var rand = function (min, max) {
            return Math.random() * (max - min) + min;
            return (Math.random() * max) + min;
        }

        self.initialize();
        return self;
    }

    window.log = function f() {
        log.history = log.history || [];
        log.history.push(arguments);
        if (this.console) {
            var args = arguments,
                newarr;
            args.callee = args.callee.caller;
            newarr = [].slice.call(args);

            if (typeof console.log === 'object') log.apply.call(console.log, console, newarr);
            else console.log.apply(console, newarr);
        }
    };
    (function (a) {
        function b() {}

        for (var c = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","), d; !!(d = c.pop());) {
            a[d] = a[d] || b;
        }
    })

    (function () {
        try {
            console.log();
            return window.console;
        } catch (a) {
            return (window.console = {});
        }
    }());
</script>

我已经被困在代码中的这一点上大约一个星期了,并且可以真正做一些天才的帮助!

目的:

  • 添加相当于图像阵列长度的球。
  • 每个球都有各自的图像作为中心背景。
  • 球不会离开画布的边界。

相关代码:

  • initBalls()
  • addBall()

谢谢你,杰森。

javascript html5 canvas
1个回答
1
投票

https://codepen.io/prtjohanson/pen/vPKQBg

需要改变什么:

for (let i = 0; i < imagesArray.length; i++) {
  console.log(i);

  const imageArray = imagesArray[i];

  setTimeout(function() {
    var arrayImage = new Image();

    arrayImage.onload = function() {
      addBall(arrayImage, stageX / 2, 0);
    };

    arrayImage.src = imageArray;
  }, i * 1000);
}

当setTimeout回调被触发时,你的for循环已经完成并且使用var声明,for循环迭代没有自己的范围,有了let,每个迭代都有自己的范围,就像函数一样。

如果它必须在没有let或const关键字的浏览器上运行,请告诉我,我也可以为它们提供解决方案

这将适用于IE11和其他不支持ES6的浏览器

 for (var i = 0; i < imagesArray.length; i++) {
  (function(imageArray) {

    setTimeout(function() {
      var arrayImage = new Image();

      arrayImage.onload = function() {
        console.log('Add'+i);
        addBall(arrayImage, stageX / 2, 0);
      };

      arrayImage.src = imageArray;
    }, i * 1000);
  })(imagesArray[i]);
}

要使图像居中,不使它们超出画布边界,请对beginBitmapFill操作使用2D变换:

var transform = new createjs.Matrix2D();
transform.appendTransform(-shape.radius, -shape.radius, 1, 1, 0);
shape.graphics.beginBitmapFill(img, "repeat", transform).drawCircle(0, 0, shape.radius);

至于没有像数组中的URL一样多的球,似乎有时图像源URL提示“我不是机器人”验证码。如果用您控制下的URL-s替换,问题应该消失。

© www.soinside.com 2019 - 2024. All rights reserved.