Question

I am learning the basics of a physics engine using javascript and wanting to have all of the engine and the game data held within an object, but have been unable to use the 'this' keyword when recursively calling the draw function to animate the scene. I can successfully call the separate draw function that works, but won't be as easy to implement more than one object to animate

here is a simple codepen with a working testbed.

here is the page

<!doctype html>
<html>

<head>

<style type="text/css">

    #obj{
        width: 50px;
        height: 200px;
        background: red;
        position: absolute;
        left: 100px;
        bottom: 200px;
    }

    #ground{
        width: 100%;
        height: 200px;
        background: #222;
        position: absolute;
        bottom: 0;
        left: 0;
    }

</style>


</head> 

<body>

<div id="content">

<section>
    <button onclick="draw()">draw()</button><br>
    <button onclick="obj.draw()">obj.draw()</button>
</section>

<article>

    <div id="obj"></div>
    <div id="ground"></div>

</article>  

</div> <!-- END CONTENT -->

</body>

<script type="text/javascript">

var obj = {
    // variables
    id: 'obj',
    width: 50,
    height: 200,
    angle: 30,
    speed: 20,
    acceleration: 4/60,
    deceleration: 2/60,
    moving: false,
    jumping: false,
    // Get methods
    x: function(){return parseInt(window.getComputedStyle(document.getElementById(this.id)).left)},
    y: function(){return parseInt(window.getComputedStyle(document.getElementById(this.id)).bottom)},
    // engine methods
    scale_x: function(){return Math.cos((this.angle * Math.PI) / 180)},
    scale_y: function(){return Math.sin((this.angle * Math.PI) / 180)},
    velocity_x: function(){return this.speed * this.scale_x()},
    velocity_y: function(){return this.speed * this.scale_y()},
    cx: function(){return this.x() + this.width},
    cy: function(){return this.y() + this.height},
    // set methods
    setAngle: function(val){this.angle = val},
    setAcceleration: function(val){this.acceleration = val / 60},
    setDeceleration: function(val){this.deceleration = val / 60},
    setSpeed: function(val){this.speed = val},
    setMoving: function(val){this.moving = val},
    setJumping: function(val){this.jumping = val},
    draw: function(){
        document.getElementById(this.id).style.left = (this.speed++) + 'px';
        window.requestAnimationFrame(this.draw);
    }
}

function draw(){
    document.getElementById(obj.id).style.left = (obj.speed++) + 'px';
        window.requestAnimationFrame(draw);
}

</script>   

</html> 

thanks for any help,

Andrew

Était-ce utile?

La solution

Observe that you call obj.draw as :

<button onclick="obj.draw()

The first time obj.draw is called, the context is different than when it called by requestAnimationFrame multiple times, as a callback function before the repaint.

So try by saving this in a variable which is outside the scope of the callback function.

Something like :

var obj = {    
    //...

    draw: function () {
        var sender = this;
        var draw = function () {
            document.getElementById(sender.id).style.left = (sender.speed++) + 'px';
            window.requestAnimationFrame(draw);
        }
        draw();
    }
}

Here is an updated demo of how this would look like.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top