Jump to content

Move Sprite by Touch, with Joystick Image


paulmo

Recommended Posts

My canvas sprite (man) moves by arrow keys, now I need sprite man to move by touch, using either an image or canvas-rendered shape in corner of screen (testing with Chrome's Emulator). This joystick image/shape will control (up/down/left/right) sprite man.

 

I've done MDN's tutorial, which draws lines along finger movement; I've done Austin Hallock's demo, which shows coordinates as finger moves around virtual joystick, but I'm not finding how to control a sprite with another image or canvas-rendered shape.

 

So my setKey function and associated document.addEventListener in the "arrow key" section of my game needs to correspond to canvas image/area whose touch events make sprite man move.

 

Help greatly appreciated for pointing me in right direction.

 

 

Edited by paulmo
Link to comment
Share on other sites

If you use Austin Hallock's script you just need to listen for the touchStart, touchMove and touchEnd events.

 

You check the values of normalizedX and normalizedY to determine which direction to move. This is really simple but it's an example. I don't know what mechanics you use to move your character, and that makes a difference.

GameController.init({    left: {        type: 'joystick',        joystick : {            touchMove : function(data) {                if(data.normalizedX < -0.2) {                   // Move the guy left                }                if(data.normalizedX > 0.2) {                   // Move the guy right                }            },            touchEnd : function(data) {                // Set the velocity to zero            }        }    }});
Link to comment
Share on other sites

Thanks, these are mechanics functions; please suggest how apply to touchMove conditional:

(function() {var pressedKeys = {}; function setKey(event, status) {var code = event.keyCode;var key;  switch(code) {case 32: key = "SPACE"; break; // shoots bulletscase 37: key = "LEFT"; break; case 38: key = "UP"; break; case 39: key = "RIGHT"; break;case 40: key = "DOWN"; break;default: }pressedKeys[key] = status; }document.addEventListener("keydown", function(e) {setKey(e, true);});document.addEventListener("keyup", function(e) {setKey(e, false);});window.addEventListener("blur", function() {pressedKeys = {};}); 
function handleInput(dt) {if(input.isDown("DOWN") || input.isDown("s")) { // move sprite man virtual joystickplayer.pos[1] += playerSpeed * dt;}if(input.isDown("UP") || input.isDown("w")) {player.pos[1] -= playerSpeed * dt;}if(input.isDown("LEFT") || input.isDown("a")) {player.pos[0] -= playerSpeed * dt;}if(input.isDown("RIGHT") || input.isDown("d")) {player.pos[0] += playerSpeed * dt;}
Edited by paulmo
Link to comment
Share on other sites

In the touchMove event, decide a threshold which you consider the minimum distance the stick should move before you consider the direction pressed. In my previous example I used 0.2.

 

You probably should have a setKey function that doesn't depend on Javascript event objects. Deal with the event object in the event handler itself rather than sending it to the setKey function. I'll work with what you've built, though, and create fake event objects.

// A constantvar THRESHOLD = 0.2;// The event listenerstouchMove : function(data) {    // Horizontal    if(data.normalizeX  < -THRESHOLD) {        setKey({ keyCode : 37 }, true);    } else if(data.normalizeX > THRESHOLD) {        setKey({ keyCode : 39 }, true);    } else {        setKey({ keyCode : 37 }, false);        setKey({ keyCode : 39 }, false);    }    // Vertical    if(data.normalizeY  < -THRESHOLD) {        setKey({ keyCode : 40 }, true);    } else if(data.normalizeY > THRESHOLD) {        setKey({ keyCode : 38 }, true);    } else {        setKey({ keyCode : 40 }, false);        setKey({ keyCode : 38 }, false);    }},touchEnd : function(data) {    // I assume when the player stops touching the joystick it goes back to neutral    setKey({ keyCode : 37 }, false);    setKey({ keyCode : 38 }, false);    setKey({ keyCode : 39 }, false);    setKey({ keyCode : 40 }, false);}
Link to comment
Share on other sites

Update: controller is rendering (but not functioning, setKey is not defined: Un(setKey({ keyCode : 37 }, false);, and controller only renders if I include another canvas element in game...

<canvas id= "canvas" width= "512" height="480"></canvas>

...on top of pre-existing game canvas:

var canvas = document.createElement("canvas");canvas.id = "2d";var ctx = canvas.getContext("2d");canvas.width = 512;canvas.height = 480;document.body.appendChild(canvas);

I'm stumped...Hallock's gamecontroller.js should be overlaying its own canvas for the controller...I'm noticing that controller's canvas should be document.body.appendChild(canvas), same as my game canvas...does this create a conflict?

/ Grab the canvas if one wasn't passed            var ele;            if( !this.options.canvas || !( ele = document.getElementById( this.options.canvas ) ) )            {                this.options.canvas = document.getElementsByTagName( 'canvas' )[0];            }            else if( ele )            {                this.options.canvas = ele;            }                        this.options.ctx = this.options.canvas.getContext( '2d' );                        // Create a canvas that goes directly on top of the game canvas            this.createOverlayCanvas();        },                /**         * Finds the actual 4 corners of canvas that are being used (so we don't have to clear the entire canvas each render)          * Called when each new touchableArea is added in         * @param {object} options - x, y, width, height         */        boundingSet: function( options ) {            var directions = ['left', 'right'];                        // Square - pivot is top left            if( options.width )            {                var width = this.getPixels( options.width );                var height = this.getPixels( options.height );                var left = this.getPixels( options.x );                var top = this.getPixels( options.y );            }            // Circle - pivot is center            else            {                if( this.options.touchRadius )                    var radius = this.getPixels( options.radius ) * 2 + ( this.getPixels( this.options.touchRadius ) / 2 ); // size of the box the joystick can go to                else                    var radius = options.radius;                var width = height = ( radius + this.getPixels( options.stroke ) ) * 2;                var left = this.getPixels( options.x ) - ( width / 2 );                var top = this.getPixels( options.y ) - ( height / 2 );            }            var right = left + width;            var bottom = top + height;                        if( this.bound.left === false || left < this.bound.left )                this.bound.left = left;            if( this.bound.right === false || right > this.bound.right )                this.bound.right = right;            if( this.bound.top === false || top < this.bound.top )                this.bound.top = top;            if( this.bound.bottom === false || bottom > this.bound.bottom )                this.bound.bottom = bottom;        },                /**         * Creates the canvas that sits on top of the game's canvas and holds game controls          */        createOverlayCanvas: function() {            this.canvas = document.createElement( 'canvas' );                        // Scale to same size as original canvas            this.resize( true );                        document.getElementsByTagName( 'body' )[0].appendChild( this.canvas );            this.ctx = this.canvas.getContext( '2d' );                        var _this = this;            window.addEventListener( 'resize', function() {                // Wait for any other events to finish                setTimeout( function() { GameController.resize.call( _this ); }, 1 );            } );                                    // Set the touch events for this new canvas            this.setTouchEvents();                        // Load in the initial UI elements            this.loadSide( 'left' );            this.loadSide( 'right' );                        // Starts up the rendering / drawing            this.render();                        if( ! this.touches || this.touches.length == 0 )                this.paused = true; // pause until a touch event        },                pixelRatio: 1,        resize: function( firstTime ) {            // Scale to same size as original canvas            this.canvas.width = this.options.canvas.width;            this.canvas.height = this.options.canvas.height;                        this.offsetX = GameController.options.canvas.offsetLeft + document.body.scrollLeft;            this.offsetY = GameController.options.canvas.offsetTop + document.body.scrollTop;                        // Get in on this retina action            if( this.options.canvas.style.width && this.options.canvas.style.height && this.options.canvas.style.height.indexOf( 'px' ) !== -1 )             {                this.canvas.style.width = this.options.canvas.style.width;                this.canvas.style.height = this.options.canvas.style.height;                this.pixelRatio = this.canvas.width / parseInt( this.canvas.style.width );            }                        this.canvas.style.position = 'absolute';            this.canvas.style.zIndex = '5';            this.canvas.style.left = this.options.canvas.offsetLeft + 'px';            this.canvas.style.top = this.options.canvas.offsetTop + 'px';            this.canvas.setAttribute( 'style', this.canvas.getAttribute( 'style' ) +' -ms-touch-action: none;' );            
Edited by paulmo
Link to comment
Share on other sites

To fix the first problem make your setKey() function global so that it's accessible from anywhere. Take it outside of the function wrapper.

 

I haven't read all the documentation for this person's controller library. It might be a good exercise for you to read it and see what it says. It probably explains how it works. If creating a new canvas element solves the problem then that's probably what you should do.

Link to comment
Share on other sites

Thanks, making setKey() global fixed that error. I have read through the library. Creating a new canvas element renders the controller, but it doesn't solve the problem of overlaid canvas controller layer 1) not moving the man sprite and 2) blocking touch response to underlying game layer. For example game reset button doesn't work when controller layer is applied. So the controller is not moving the man sprite, and it's blocking (not visually) functionality of the game layer.

Link to comment
Share on other sites

Have you tried passing your own game's canvas to the controller? Perhaps this library has a method that allows you to tell it when to render the objects so that they won't be under other objects you draw.

 

If you can't do that, then consider using the controller's canvas for all your inputs. Keep a reference to it and draw on it.

 

I'm not sure it will work because they might be erasing everything before redrawing.

Link to comment
Share on other sites

Have you tried passing your own game's canvas to the controller?

My canvas variable and controller's were named the same, and both appendChild elements, so I renamed my canvas variable and that didn't change anything. Also, I see now library converts physical keyboard events to touch responses (snippet):

right: {                        width: '15%',                        height: '7%',                        stroke: 2,                        touchStart: function() {                            GameController.simulateKeyEvent( 'press', 39 );                            GameController.simulateKeyEvent( 'down', 39 );                        },                        touchEnd: function() {                            GameController.simulateKeyEvent( 'up', 39 );

so I commented out event listeners previously included in game section:

// The event listenerstouchMove : function(data) { //etc.

that doesn't change anything either: the controller is rendered on top of my game, but there's no functionality.

consider using the controller's canvas for all your inputs. Keep a reference to it and draw on it.

 

 

I don't know how to do that...looking at controller library, this should be seamless. If I wanted to do finger doodles on my phone I'd be all set: that's what docs focus on, including MDN.

Edited by paulmo
Link to comment
Share on other sites

Starting fresh, trying to move a rectangle with virtual joystick (touch only). Joystick and rectangle are rendering in canvas and coordinate alerts are working when using joystick. Now how do I fit these functions to move the rectangle? The rectangle should move in proportion to X/Y joystick movement. Thanks in advance for direction.

<script>function shape() {    var cs = document.getElementById("2d");    var ctx = cs.getContext("2d");    ctx.clearRect(0, 0, 300, 90);    ctx.beginPath();    ctx.rect(80, 60, 140, 70);    ctx.fillStyle="blue";    ctx.fill();} </script></head><body onload = "shape()"><script>GameController.init( { //gamecontroller.js in head    left: {        type: 'joystick',         joystick: {        touchMove : function(data) {            if(data.normalizedX < -0.1 && data.normalizedY < 0.1) { // Move/translate Rect. here. Alerts work!
Cont'd...
 alert("left, down")             }                else if(data.normalizedX < -0.1 && data.normalizedY > 0.1) {            alert("left, up")            }            else if(data.normalizedX > -0.1 && data.normalizedY < 0.1) {            alert("right, down")            }             else {            alert("right, up")              }                
Edited by paulmo
Link to comment
Share on other sites

Videogames have what's called a "game loop" that runs periodically. For the game loop we can have a function that's being called by setInterval() or setTimeout() (or the more recent requestAnimationFrame())

 

There are many different "layers" in a videogame. For your example we just need two: The data and the graphics.

 

On each game loop you first update the data, then the graphics layer goes through all the objects in the data layer and renders them. Because graphics are more intensive on the processor, sometimes the graphics layer is updated less frequently than the data layer is.

 

For your example you'll have an object we can call "rectangle" with an X position, a Y position, an X velocity and a Y velocity.

var rectangle = {    x : 0,    y : 0,    vx : 0,    vy : 0};

Since this game controller library is event driven, you're going to need a buffer for which buttons have been pressed and released. There are so many different possible ways to represent that with a data structure. To make it simple for you, just a plain object will work:

var inputBuffer = {    up : false,    down : false,    left : false,    right : false,    action : false};

When the virtual controller fires an event you set the values of this object to true or false based on whether the button was pressed or released. For the directions, remember that when up is true down has to be false and vice versa, same for left and right.

 

On each game loop you will read the values in the input buffer and update the velocities and positions of the rectangle object based on their values. After that, you have a part of the game loop that reads the values in the rectangle object and draws the rectangle in a particular position.

 

 

Game development is not easy. If you don't yet have the skills to do it on your own then you should do a lot more research or advance your career with additional formal education, because this is hardly even the tip of the iceberg.

Link to comment
Share on other sites

Thanks for notes about game loop, inputBuffer and values updates. For starters I'll just move a shape along a line for various touches (left/down, left/up etc.). I'm aware that game dev is hard and moving a shape with a joystick is basic for most. Thanks again for showing how normalizedX and Y fits in the main function. I'm able to get alerts on that and render different shapes for touch areas on the joystick, which is a start.

Link to comment
Share on other sites

I'm back, with working gameloop and requestAnimationFrame, but still unsure where to include GameController function so that it interfaces with the underlying game; if I include GameController high up in body, it overlays on the canvas (in a separate layer so that game reset button cannot be clicked at that point), or if I wrap GameController function around the game's setKey section (shown below), the game and the controller both do not render at all. The gamecontroller.js script detects a game's keyboard mapping and applies that to a d-pad, so GameController.init() should work out of the box if I put it in the right place:

GameController.init( {    left: {        type: 'joystick'  // needs to apply to cases 37, 38, 39, 40 (below)    },     right: {        position: {           // right: '5%'        },        type: 'buttons',        buttons: [        {            label: 'Zap!', fontSize: 13, touchStart: function() {                // this needs to be case 32 SPACE key section (below)            }        },        false, false, false        ]   } }); // end GameController()

 

Again here is the functioning keyboard command section of game! (gamecontroller.js script mirrors these mappings exactly.)

(function() {var pressedKeys = {};  function setKey(event, status) {var code = event.keyCode;var key;  switch(code) {case 32: key = "SPACE"; break;case 37: key = "LEFT"; break; case 38: key = "UP"; break; case 39: key = "RIGHT"; break;case 40: key = "DOWN"; break;default: //ASCII to letterskey = String.fromCharCode(code);}pressedKeys[key] = status; }document.addEventListener("keydown", function(e) {setKey(e, true);});document.addEventListener("keyup", function(e) {setKey(e, false);});window.addEventListener("blur", function() {pressedKeys = {};});window.input = {isDown: function(key) {return pressedKeys[key.toUpperCase()];}};     

Ignolme, your previous normalizedX and Y comments enabled me to do interesting things like draw circles along a line or vector for different coordinate touches, but the gamecontroller.js script converts whatever is happening in keyboard mappings, to touch controller...I'm just not applying it correctly...so any suggestion greatly appreciated.

Link to comment
Share on other sites

The documentation for that game controller library doesn't seem to have a lot of information, they don't explain how it checks for keyboard mappings if it does at all.

 

This script is working, I tested it in my Firefox's mobile emulator. Look through it and try to see what you were missing in your own attempts:

<!DOCTYPE html><html>    <head>        <title>Game Controller test</title>    </head>    <body>        <canvas id="game" width="800" height="600"></canvas>        <script src="gamecontroller.min.js"></script>        <script>            // Constants            var MIN_SPEED = 0;            var MAX_SPEED = 20;            var ACCELERATION = 0.5;            var JOYSTICK_THRESHOLD = 0.2;            var INV_FRICTION = 0.6;            var BOX_SIZE = 40;            // Game objects            var canvas = document.getElementById("game");            var context = canvas.getContext("2d");            var inputBuffer = {                up : false,                down : false,                left: false,                right: false            };            var box = {                x : 400,                y : 300,                vx : 0,                vy : 0            };            // The game loop            function gameLoop() {                setTimeout(gameLoop, 33);                /* Check inputs */                // Vartical inputs                if(inputBuffer.up) {                    // Move up                    box.vy -= ACCELERATION;                } else if(inputBuffer.down) {                    // Move down                    box.vy += ACCELERATION;                } else {                    // Vertical friction                    box.vy *= INV_FRICTION;                    if(box.vy < MIN_SPEED && box.vy > -MIN_SPEED) {                        box.vy = 0;                    }                }                // Horizontal inputs                if(inputBuffer.left) {                    // Move left                    box.vx -= ACCELERATION;                } else if(inputBuffer.right) {                    // Move right                    box.vx += ACCELERATION;                } else {                    // Horizontal friction                    box.vx *= INV_FRICTION;                    if(box.vx < MIN_SPEED && box.vx > -MIN_SPEED) {                        box.vx = 0;                    }                }                /* Prevent the box from going too fast */                if(box.vx > MAX_SPEED) {                    box.vx = MAX_SPEED;                }                if(box.vx < -MAX_SPEED) {                    box.vx = -MAX_SPEED;                }                if(box.vy > MAX_SPEED) {                    box.vy = MAX_SPEED;                }                if(box.vy < -MAX_SPEED) {                    box.vy = -MAX_SPEED;                }                /* Update the box's position */                box.x += box.vx;                box.y += box.vy;                                /* Draw everthing */                // Clear the screen                context.clearRect(0, 0, canvas.width, canvas.height);                // Draw the box                context.fillStyle = "red";                context.fillRect(box.x, box.y, BOX_SIZE, BOX_SIZE);            }            // Initialize the controller            GameController.init({                left: {                    type: 'joystick',                    joystick : {                        touchMove : function(data) {                            // Horizontal controls                            if(data.normalizedX < -JOYSTICK_THRESHOLD) {                                // Left                               inputBuffer.left = true;                               inputBuffer.right = false;                            } else if(data.normalizedX > JOYSTICK_THRESHOLD) {                                // Right                               inputBuffer.right = true;                               inputBuffer.left = false;                            } else {                                // Neutral                                inputBuffer.left = false;                                inputBuffer.right = false;                            }                            // Vertical controls                            if(data.normalizedY < -JOYSTICK_THRESHOLD) {                               inputBuffer.down = true;                               inputBuffer.up = false;                            } else if(data.normalizedY > JOYSTICK_THRESHOLD) {                               inputBuffer.up = true;                               inputBuffer.down = false;                            } else {                               inputBuffer.up = false;                               inputBuffer.down = false;                            }                        }                    }                }            });            // Begin the game            gameLoop();        </script>    </body></html>
Link to comment
Share on other sites

  • 2 months later...

Re-visiting this topic. I've rotated the square. Initial position of rotated square is to the left of joystick. I want another square (square 2) to appear in upper right quadrant of screen, if square 1 crosses y/2 (y > 0). How to do this? I'm attaching code for reference. Thanks.

// BOX OBJECT, x y sets initial star position            var box = {                x : 330,                y : 170,                vx : 0,                vy : 0            };                        // rotating            var cx = BOX_SIZE/2;            var cy = BOX_SIZE/2;            var x = -10;            var y = -10;            var w = 30;            var h = 30;            var deg = 45;            // The game loop            function gameLoop() {                setTimeout(gameLoop, 33);                /* Check inputs */                // Vartical inputs                if(inputBuffer.up) {                    // Move up                    box.vy -= ACCELERATION;                } else if(inputBuffer.down) {                    // Move down                    box.vy += ACCELERATION;                } else {                    // Vertical friction                    box.vy *= INV_FRICTION;                    if(box.vy < MIN_SPEED && box.vy > -MIN_SPEED) {                        box.vy = 0;                    }                }                // Horizontal inputs                if(inputBuffer.left) {                    // Move left                    box.vx -= ACCELERATION;                } else if(inputBuffer.right) {                    // Move right                    box.vx += ACCELERATION;                } else {                    // Horizontal friction                    box.vx *= INV_FRICTION;                    if(box.vx < MIN_SPEED && box.vx > -MIN_SPEED) {                        box.vx = 0;                    }                }                /* Prevent the box from going too fast */                if(box.vx > MAX_SPEED) {                    box.vx = MAX_SPEED;                }                if(box.vx < -MAX_SPEED) {                    box.vx = -MAX_SPEED;                }                if(box.vy > MAX_SPEED) {                    box.vy = MAX_SPEED;                }                if(box.vy < -MAX_SPEED) {                    box.vy = -MAX_SPEED;                }                /* Update the box's position */                box.x += box.vx;                box.y += box.vy;                                /* Draw everthing */                // Clear the screen                context.clearRect(0, 0, canvas.width, canvas.height);                            // BOX OBJECT DRAW                context.save();                context.fillStyle = "#f0ffff";                context.translate(cx, cy);                 context.rotate(deg * Math.PI/180);                context.fillRect(box.x, box.y, BOX_SIZE, BOX_SIZE);                context.restore();    }            // Initialize the controller            GameController.init({                right: { // WAS LEFT                    type: 'joystick',                    joystick : {                        touchMove : function(data) {                            // Horizontal controls                            if(data.normalizedX < -JOYSTICK_THRESHOLD) {                                // Left                               inputBuffer.left = true;                               inputBuffer.right = false;                            } else if(data.normalizedX > JOYSTICK_THRESHOLD) {                                // Right                               inputBuffer.right = true;                               inputBuffer.left = false;                            } else {                                // Neutral                                inputBuffer.left = false;                                inputBuffer.right = false;                            }                            // Vertical controls                            if(data.normalizedY < -JOYSTICK_THRESHOLD) {                               inputBuffer.down = true;                               inputBuffer.up = false;                            } else if(data.normalizedY > JOYSTICK_THRESHOLD) {                               inputBuffer.up = true;                               inputBuffer.down = false;                            } else {                               inputBuffer.up = false;                               inputBuffer.down = false;                            }                        }                    }                }            });            // Begin the game            gameLoop();
Edited by paulmo
Link to comment
Share on other sites

What is y / 2? Do you mean half of the viewport's height?

 

On each game loop, test the position of the rectangle. If the rectangle's Y position is within the rage you're testing for, create another rectangle object with the size, position and other attribuets you want it to have

 

Normally in a videogame you have a list of sprites (your "box" object could be considered a sprite). You can use an array for that. You can add sprites or remove sprites from that array. On each game cycle, the program would go through the list of sprites, update their attributes and then draw them one by one. You can use a for() loop to traverse the array.

Link to comment
Share on other sites

What is y / 2? Do you mean half of the viewport's height?

Yes, if Box sprite's y position > 0 then a 2nd sprite will appear at a different position. I'll work on testing sprite position on each game loop, and putting new sprites in an array. I'm sure I'll be back here later. Thanks Ingolme.

Link to comment
Share on other sites

Everything works below, except the 2nd spite (TWO) re-appears when BOX moves outside of the position defined in for loop below. Also, BOX reverts to its old color when outside of position in for loop. I need TWO to disappear for the entire game, and BOX to retain new color, after BOX arrives at TWO's position. Thanks for help.

                for(i = box.y; i < 69; i++) { // Check BOX position and render "TWO"                     context.save();                    context.fillStyle = "#f0ffff";                    context.translate(cx, cy);                    context.rotate(deg * Math.PI/180);                    context.fillRect(two.x, two.y, TWO_SIZE, TWO_SIZE);                    context.restore();            }                for(i = box.y,  j = box.x; i < -115 && j  > 155; i++, j++) {                    console.log("Yes"); // check that BOX is in TWO's position                                context.clearRect(0, 0, canvas.width, canvas.height); // Make TWO disappear                 context.save();                context.fillStyle = "#f0bbbb"; // change BOX color                context.translate(cx, cy);                context.rotate(deg * Math.PI/180);                context.fillRect(box.x, box.y, BOX_SIZE, BOX_SIZE);                context.restore();            }            console.log("X = " + box.x);            console.log("Y = " + box.y);
Edited by paulmo
Link to comment
Share on other sites

                for(i = box.y; i < 69; i++) { // Check BOX position and render "TWO"                     context.save();                    context.fillStyle = "#f0ffff";                    context.translate(cx, cy);                    context.rotate(deg * Math.PI/180);                    context.fillRect(two.x, two.y, TWO_SIZE, TWO_SIZE);                    context.restore();            }
Why is that code inside a loop? You're looping over the variable i but you don't use i inside the loop. The same with the following loop, you're doing the same thing there.
Link to comment
Share on other sites

I don't use i inside the loop because I'm just checking to see where box object is (that's what i is doing, box object is the one moved by virtual controller), then if box is in that range, create object "two" and so on. The problem is that when box goes out of the range defined in for loop, newly created object "two" disappears and color reverts to old color. So I need the changes to stick and not revert back. How to do that?

Link to comment
Share on other sites

I don't use i inside the loop because I'm just checking to see where box object is

You only need to do that once though, why check the same position multiple times? That loop takes microseconds to execute, the position isn't going to change in that time. Moreover, you're not checking anything, there's no if statement, you're just running a bunch of code to draw stuff. If you're trying to check if i is less than 69 then use an if statement, not a loop.Do you have an example of this online somewhere?
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...