opengl – Applying spacing between moving, rotated rectangles

I am trying to implement basic Snake game with movement based on timestep. For now I’ve got something along those lines:

Update function:

glm::vec2 headPosition = glm::vec2(m_segments.begin()->m_sprite.get_position());
float angle = m_segments.begin()->m_sprite.get_angle();

m_segments.begin()->move();
    
for (auto it = m_segments.begin() + 1; it != m_segments.end(); it++)
{
    glm::vec2 oldPosition = it->m_sprite.get_position();
    float oldAngle = it->m_sprite.get_angle();

    it->m_sprite.set_position(headPosition);
    it->m_sprite.set_angle(angle);

    headPosition = oldPosition;
    angle = oldAngle;
}

Move function:

glm::vec2 position(m_sprite.get_position());
position.x +=  cosf(glm::radians(90.0f - m_sprite.get_angle())) * VELOCITY_SCALAR;
position.y += -sinf(glm::radians(90.0f - m_sprite.get_angle())) * VELOCITY_SCALAR;

m_sprite.set_position(position);

Basically I set next segment position to the old position of previous segment. As expected spacing between those segments is equal to timestep value. How can I calculate position so I can manipulate spacing between those segments?

unity – How to keep player rotated toward a sphere when within a certain radius?

In my game the player can fly to multiple spheres, I want to make it so that when the player gets within a certain distance of the sphere, (maybe using a bigger is trigger sphere collider around it?) their feet will stay pointing towards the sphere until they leave the radius, (maybe using a quaternion?) then if they get within the radius of a different sphere, their feet will point towards that too. How can I make this work? I don’t know too much about c#, so any example code would help a lot too!

Unity 3D Imported Assets Rotated Backwards in-game

I’m putting together boilerplate for a Unity FPS game, and having an issue with importing an Asset Store model.

All of my weapons are asset store prefabs. I’m new to Unity, but this makes me think there’s something about the imported prefabs themselves that’s setting the axis alignment of the models in-game.

Anyone know what I’m missing to fix this and rotate that model in the world (without just writing a model script to rotate it programmatically every time) ?

Weapon Prefabs

M4 in world

geometry – how to convert an X,Y motion based on a rotated point to X,Y motion on a coordinate grid?

I need to move a point “A” that is rotated by “B” degrees by “C” squares to it’s left, and “D” squares up. However I am only allowed to specify motion in (X motion, Y motion) based around a regular upright coordinate grid. So how do I calculate the motion in the global X,Y motiond when given the local B rotation, and C and D motions? I am programming a game and I need to know how to move my character sideways and forward using only global x and y motion.

Textures rotated 90 degrees when importing a .glb file

I have a simple box, textured with bricks, in Blender:

enter image description here

I export this scene as glTF 2.0 and import into Godot. Here’s the result:

1

As you can see, the bricks are rotated 90 degrees for some reason. Why, and how can I make it right?

javascript – JS + CANVAS Projectile Motion, problem drawing rotated images + improvements & sugestions

now just as the title says, i’ve got some JS code.

So basically it is a projectile motion thingy, i’m quite proud that i’ve actually got it working!

Basically you’ve got a canvas, and you can click it to launch a ball in a cerain angle and speed, everything is working fine, er.. except for the arrow tip of the vector thingy, can’t get that sucker to draw correctly.

So, how should i approach the arrow tip thing? i mean, how to draw it at the correct position and angle (so basically the TRANSLATE and ROTATE functions). That’s the thing that i want to solve right now.

And also, if you do take your time to go throguh the code, i’m open to suggestions and improvements, i do want to learn more about canvas and it’s best practices.

So hyped to hear your two cents on this! thx :p

First off, the HTML:

<html lang="es">
    <head>
        <meta charset="utf-8">
        <title>Projectile Motion</title>
        <link rel="stylesheet" href="index.css">
    </head>
    
    <body>
        
        <h3 id="fpsIndicator">FPS: 0</h3>
        
        <h3 id="mouse">X:0  Y:0</h3>
              
        <canvas id="area" height=500 width=1700></canvas>
        
        <p id="collision">collision indicator</p>
        <p id="ballCount">NºBalls: 0</p>
        
        <br>
        <br>
               
        <div id="infoarea">
           
            <!-- triangle-->
            <div style="border: 1px solid black; width: 220px; padding: 3px;">
                <h2 style="text-align: center;">TRIANGLE</h2>

                <h3 id="hypotenuse">hypotenuse: 0</h3>

                <h3 id="adj">adjacent: 0</h3>
                <h3 id="opp">opposite: 0</h3>
                <h3 id="theta">&theta;: 0.00º</h3>
                <h3 id="currentRads"></h3>
            </div>
            
            <!-- motion input -->
            <div style="border: 1px solid black; width: 220px; padding: 3px;">
                <h2 style="text-align: center;">MOTION INPUT</h2>

                
                <div>
                    <p>Launch Velocity (m/s)</p>
                    <input type="number" id="velocity">
                </div>
                
                <div>
                    <p>Launch Angle (degrees)</p>
                    <input type="number" id="launchAngle">
                </div>
                
                <div>
                    <p>Vertical Acceleration (gravity)</p>
                    <select name="" id="acceleration">
                        <option value="-3.7">Mercury (3.7 m/s)</option>
                        <option value="-8.87">Venus (8.87 m/s)</option>
                        <option selected value="-9.807">Earth (9.807 m/s)</option>
                        <option value="-3.711">Mars (3.711 m/s)</option>
                        <option value="-24.79">Jupiter (24.79 m/s)</option>
                        <option value="-10.44">Saturn (10.44 m/s)</option>
                        <option value="-8.87">Uranus (8.87 m/s)</option>
                        <option value="-11.15">Neptune (11.15 m/s)</option>
                        <option value="-0.62">Pluto (0.62 m/s)</option>
                        <option value="-5000">STRONK GRAVITY (5000m/s)</option>
                    </select>
                </div>
                
            </div>
            
            <!-- motion data -->
            <div style="border: 1px solid black; padding: 3px;">
                <h2 style="text-align: center;">PREDICTED MOTION DATA</h2>

                <div id="container">
                  
                   <!-- fields -->
                   <div class="subcontainer">
                        <div>
                            <p>Vertical Velocity (m/s)</p>
                            <input type="number" id="Yvel">
                        </div>

                        <div>
                            <p>Horizontal Velocity (m/s)</p>
                            <input type="number" id="Xvel">
                        </div>

                        <div>
                            <p>Flight Time (seconds)</p>
                            <input type="number" id="time">
                        </div>
                    </div>
                    
                    <!-- fields 2 -->
                    <div class="subcontainer">
                        <div>
                            <p>Max Height achieved (m)</p>
                            <input type="number" id="mHeight">
                        </div>

                        <div>
                            <p>X displacement (aprox.range)</p>
                            <input type="number" id="Xdisplacement">
                        </div>

                        <div>
                            <p>Y Acceleration (gravity)</p>
                            <input type="number" id="yAcceleration">
                        </div>
                    </div>
                    
                    
                    
                    
                </div>    
                
            </div>
            
            <!-- manual input-->
            <div style="border: 1px solid black; padding: 3px;">
               
                <h2 style="text-align: center;">MANUAL INPUT</h2>
                
                <div id="container">
                  
                   <!-- fields -->
                   <div class="subcontainer">
                       
                        <div>
                            <p>Launch Angle (degrees)</p>
                            <input type="number" id="mAngle">
                        </div>

                        <div>
                            <p>Launch Velocity (m/s)</p>
                            <input type="number" id="mVelocity">
                        </div>

                       <div style="display: flex; justify-content: center; margin-top: 3px;">
                            <button id="launchManual">
                                Launch!
                            </button>
                        </div>
                        
                    </div>
                </div>
                
                
            </div>
            
        </div>    
        
        
        <img src="theta.png" id="angle" alt="" style="display: none;">
        <img src="arrowTip.png" id="tip" alt="" style="display: none;">
    </body>
    
    <footer>
        <script src="ball.js" type="text/javascript"></script>
        <script src="index.js" type="text/javascript"></script>
    </footer>
    
</html>

Now the CSS (not much here LOL)

* {
    -webkit-user-select: none; /* Safari */        
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* IE10+/Edge */
    user-select: none; /* Standard */
}

canvas {

    height: 500px;
    width: 1700px;
    display: block;
    margin-left: auto;
    margin-right: auto;
    border: 1px solid red;
}

p {
    margin: 0;
    margin-top: 8px;
}

#infoarea {
    display: flex;
    justify-content: flex-start;
}

#container {
    display: flex;
    justify-content: space-around:
}

.subcontainer{
    margin: 4px;
    padding: 4px;
    box-shadow: 2px 2px 2px gray;
}

Now the Ball class

class Ball{
    
    
    constructor(positionP, velocityP, accelerationP, radiusP, contextP, colorP){
        
        this.radius = 15; /*radiusP;*/
        this.context = contextP;
        this.color = colorP; 
        
        this.friction = 0.97;
        this.colliding = false;
        this.collidingColor = "yellow";
        
        this.position = {
            x: positionP.x,
            y: positionP.y
        }
        
        this.velocity = {
            x: velocityP.x,
            y: velocityP.y
        }
        
        this.acceleration = {
            x : 0,
            y : accelerationP/60
        }
    }
    
    draw(){
        
        if(this.colliding) this.context.fillStyle = this.collidingColor;
        else this.context.fillStyle = this.color; 
            
        this.context.beginPath();
        this.context.arc(this.position.x, this.position.y, this.radius, 0, 2*Math.PI);
        this.context.fill();
    }
    
    move(){
               
        this.velocity.x += this.acceleration.x;
        this.velocity.y = this.velocity.y + this.acceleration.y;


        this.position.x += this.velocity.x;
        this.position.y -= this.velocity.y;
        
    }
}

And finally, the BIG one:

//screen labels
let fpsInd = document.getElementById("fpsIndicator");
let mouseInd = document.getElementById("mouse");
let hypIndicator = document.getElementById("hypotenuse");
let oppIndicator = document.getElementById("opp");
let adjIndicator = document.getElementById("adj");
let thetaIndicator = document.getElementById("theta");


let manualLauncherBtn = document.getElementById("launchManual");
let manualVelocity = document.getElementById("mVelocity");
let manualAngle = document.getElementById("mAngle");

var strThetaChar = thetaIndicator.innerHTML.split(" ")(0);
var currentThetaRadians;

var CANVAS_CLICKED = false;
let canvas = document.getElementById("area");
let ctx = canvas.getContext("2d");

var frames = 0;
var fps = 0;
var lastCallTime;

let Balls = ();

/////////////////////////motion variables//////////
let velocity_initial;
let angle;
let time;


//VERTICAL 
let y_velocity_original = 0;
let y_velocity_final = 0;
let y_original = 0;
let y_final = 0;
let y_acceleration = 0;
let max_height = 0;


//HORIZONTAL 
let x_velocity_original = 0;
let x_velocity_final = 0;
let x_original = 0;
let x_final = 0;
let x_acceleration = 0;




canvas.addEventListener('mousemove', (event)=>{
    updateMouse(event);
    solveTriangle();
});

canvas.addEventListener('click', () => {
   CANVAS_CLICKED = true;    
   MotionMain(ctx); 
});

manualLauncherBtn.addEventListener('click', () => {
   performManuaLaunch(); 
});

var origin = {
    x: 0,
    y: canvas.height
}

var originBalls = {
    x: 0,
    y: canvas.height-1
}

var mousePosition = {
    x: 0,
    y: 0
}




window.requestAnimationFrame(loop);
function loop() {
      
  frames ++;
  getFPS();
    
  console.log(CANVAS_CLICKED);    
    
  if(frames % 3 == 0) 
    fpsInd.innerHTML = "FPS: "+fps;      

  clearScreen();    
  workNextFrame();    
    

  CANVAS_CLICKED = false;    
    
  window.requestAnimationFrame(loop);  
}

//motion functions
function MotionMain(ctx){      
        
    y_acceleration = parseFloat(y_acceleration);  
    solveProblem();
    showLaunchData();
    
    newBall();
}

function performManuaLaunch(){    
    let launchData = createManualBall();
    let {ball, velocities, maxHeight, s, t} = launchData;
           
    showManualData(velocities, t, maxHeight, s);  
    Balls.push(ball);
}

function showManualData(velocities, t, maxHeight, s){
    let a = document.getElementById("acceleration").value;
    
    document.getElementById('velocity').value = manualVelocity.value;
    document.getElementById('launchAngle').value = manualAngle.value;
    document.getElementById('Yvel').value = velocities.y.toFixed(2);
    document.getElementById('Xvel').value = velocities.x.toFixed(2);
    document.getElementById('time').value = parseFloat(t).toFixed(2);
    document.getElementById('mHeight').value = parseFloat(maxHeight).toFixed(2);
    document.getElementById('Xdisplacement').value = parseFloat(s).toFixed(2);
    document.getElementById('yAcceleration').value = a;
}

function createManualBall(){
    let mTime, mDisplacementX, mMaxHeight, mBall;
    
    let m_angle = parseFloat(manualAngle.value);
    let m_vel = parseFloat(manualVelocity.value);
    
    let velY = Math.sin( (m_angle * Math.PI) / 180) * m_vel;
    let velX = Math.cos( (m_angle * Math.PI) / 180) * m_vel;
    
        
    let accelerationY = parseFloat(document.getElementById("acceleration").value);
    
    // 1- get the time -> Vf=Vo+at --> t=Vo-Vf/a
    mTime = Math.abs( velY / accelerationY )*2;
    mTime = mTime.toFixed(3);
    
    // 2- get the range -> Xf=Vo*t
    mDisplacementX = (velX * mTime).toFixed(0);
    
    // 3- get the maximum height -> Vo*Vo/2*a
    mMaxHeight = Math.abs( (velY*velY) / ( 2 * accelerationY ) ).toFixed(2);
    
    mBall = new Ball(originBalls, {
        x: velX,
        y: velY
    }, accelerationY,7, ctx, "yellow");
    
    return {
        t: mTime,
        s: mDisplacementX,
        maxHeight: mMaxHeight,
        velocities: {x: velX, y: velY},
        ball: mBall
    }
}


function solveProblem(){
    
    time = 0;
    x_final = 0;
    max_height = 0;
        
    // 1- get the time -> Vf=Vo+at --> t=Vo-Vf/a
    time = Math.abs( (y_velocity_original - y_velocity_final) / y_acceleration )*2;
    time = time.toFixed(3);
    
    // 2- get the range -> Xf=Vo*t
    x_final = (x_velocity_original * time).toFixed(0);
    
    // 3- get the maximum height -> Vo*Vo/2*a
    max_height = Math.abs( (y_velocity_original*y_velocity_original) / (2*y_acceleration) ).toFixed(2);  
    
    //alert("time: "+time+"s range: "+x_final+"m Max.Height: "+max_height+"m");
}

function showLaunchData(){
    document.getElementById('velocity').value = velocity_initial;
    document.getElementById('launchAngle').value = angle;
    document.getElementById('Yvel').value = y_velocity_original;
    document.getElementById('Xvel').value = x_velocity_original;
    document.getElementById('time').value = time;
    document.getElementById('mHeight').value = max_height;
    document.getElementById('Xdisplacement').value = x_final;
    document.getElementById('yAcceleration').value = y_acceleration;
}

function newBall(){
    
    if(!CANVAS_CLICKED) return;
    
    let c;
    
    if(angle <= 30) c = "red";
    else if(angle <= 45 && angle > 30) c = "green";
    else if(angle <= 60 && angle > 45) c = "blue";
    else if(angle <= 90 && angle > 60) c = "black";
    
      
    var ball = new Ball( originBalls, {
        x: x_velocity_original,
        y: y_velocity_original
    }, y_acceleration, 5, ctx, c);
    
    
    Balls.push(ball);
}

function randomInteger(min, max){
    return Math.floor(Math.random() * (max-min+1) + min);
}
/////////////////////////////////////////

function workNextFrame(){
    //drawVectorTip(); <- this thing right here, darn
    drawVectorLine(); 
    
    drawAngleIcon();
    drawAngleArc();
    
    
    updateBalls();
    cleanBalls();
    
    checkCollisions();
}

function updateBalls(){
    for(let i = 0; i < Balls.length; i++){       
        Balls(i).draw();
        Balls(i).move();
    }
}

function cleanBalls(){
    for(let i = Balls.length-1; i >= 0; i--){       
        let ball = Balls(i);
        if(ball.position.y > canvas.height) Balls.splice(i,1);
        document.getElementById("ballCount").innerHTML = "NºBalls: "+Balls.length;
    }
}

function drawVectorTip(){
    
    var img = document.getElementById("tip");
    
    ctx.save();
    
    ctx.translate(origin.x/2, origin.y/2);
    ctx.rotate(-currentThetaRadians);
    
    ctx.drawImage(img, mousePosition.x, mousePosition.y, 40, 40);
    
    ctx.restore();
}



function drawAngleArc(){
    
    ctx.beginPath();
    ctx.arc(origin.x, origin.y, 30, 0, -currentThetaRadians, true);
    ctx.stroke(); 
    
    //document.getElementById("currentRads").innerHTML = currentThetaRadians.toFixed(3);
}

function solveTriangle(){
    var opp = Math.floor(canvas.height - mousePosition.y);
    var adj = Math.floor(mousePosition.x);
    var hyp = Math.floor(Math.sqrt( opp*opp + adj*adj ));
    
    var thetaRadians = Math.atan(opp/adj);
    var thetaDegrees = (thetaRadians*180)/Math.PI;
    
    currentThetaRadians = thetaRadians;
    
    oppIndicator.innerHTML = `Opposite: ${opp}`;
    adjIndicator.innerHTML = `Adjacent: ${adj}`;
    hypIndicator.innerHTML = `Hypotenuse: ${hyp}`;
    
    thetaIndicator.innerHTML = strThetaChar+" "+thetaDegrees.toFixed(2)+"º";
    
    
    passMotionData(opp, adj, hyp, thetaDegrees);  
}

function passMotionData(opp, adj, hyp, thetaDegrees){
    
    velocity_initial = hyp;
    angle = thetaDegrees.toFixed(2);
    time = null; 
    
    y_velocity_original = opp;
    y_velocity_final = 0;
    y_original = canvas.height;
    y_final = canvas.height;
    y_acceleration = document.getElementById("acceleration").value;
    max_height = null;
    
    x_velocity_original = adj;
    x_velocity_final = 0;
    x_original = 0;
    x_final = null;
    x_acceleration = 0;     
}

function drawVectorLine(){
    
    ctx.beginPath();
    ctx.moveTo(origin.x, origin.y);
    ctx.lineTo(mousePosition.x, mousePosition.y);
    ctx.stroke();
    
}

function drawAngleIcon(){
  var img = document.getElementById("angle");
  ctx.drawImage(img, origin.x+5, origin.y-14, 10, 10);
}

function clearScreen(){
    ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function updateMouse(event){
  var rect = event.target.getBoundingClientRect();
     
  mousePosition.x = event.clientX - rect.left; //x position within the element.
  mousePosition.y = event.clientY - rect.top;  //y position within the element.
    
  mouseInd.innerHTML = `X: ${mousePosition.x.toFixed(0)}  Y: ${mousePosition.y.toFixed(0)}`;
}


function checkCollisions(){
    
    let first, second;
    
    for(let i = 0; i < Balls.length; i++){        
        first = Balls(i);
        
        for(let p = 0; p < Balls.length; p++){        
            second = Balls(p);
            
            if(i != p){
               if(distance(first, second) <= first.radius + second.radius) first.colliding = true;
               else first.colliding = false; 
            }            
        }
    }
}

function distance(first, second){
    let diffX = Math.abs(first.position.x - second.position.x);
    let diffY = Math.abs(first.position.y - second.position.y);
    let distance = Math.sqrt(diffX*diffX + diffY*diffY);
    
    if(distance <= first.radius + second.radius) document.getElementById("collision").innerHTML = "colliding";
    else document.getElementById("collision").innerHTML = "not colliding";
    
    return distance;
}

///funcions xungues de colisions
function rotate(velocity, angle){
    const rotatedVelocities = {
        x: velocity.X * Math.cos(angle) - velocity.Y * Math.sin(angle),   
        y: velocity.X * Math.sin(angle) + velocity.Y * Math.cos(angle)
    };
    
    return rotatedVelocities;
}


function resolveCollision(bubble, otherBubble){
    const xVelocityDiff = bubble.velocity.X - otherBubble.velocity.X;
    const yVelocityDiff = bubble.velocity.Y - otherBubble.velocity.Y;
    
    const xDist = otherBubble.x - bubble.x;
    const yDist = otherBubble.y - bubble.y;
    
    //prevent accidental overlap of bubbles
    if(xVelocityDiff * xDist + yVelocityDiff * yDist >= 0){
        
        
        //grab angle between the two colliding bubbles
        const angle = -Math.atan2(otherBubble.y - bubble.y, otherBubble.x - bubble.x);
        
        //store mass in var for better readability in collision equation
        const m1 = bubble.mass;
        const m2 = otherBubble.mass;
        
        //velocity before equation
        const u1 = rotate(bubble.velocity, angle);
        const u2 = rotate(otherBubble.velocity, angle);
        
        //velocity after 1 dimension collision equation
        const v1 = {X: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2), Y: u1.y };
        const v2 = {X: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2), Y: u2.y };
        
        //final velocity after rotating axis back to original location
        const vFinal1 = rotate(v1, -angle);
        const vFinal2 = rotate(v2, -angle);
        
        //swap bubbles velocities for realistic bounce effect
        bubble.velocity.X = vFinal1.x;
        bubble.velocity.Y = vFinal1.y;
        
        otherBubble.velocity.X = vFinal2.x;
        otherBubble.velocity.Y = vFinal2.y;
    }
}
////

function getFPS(){
    
    let delta;
    
    if(!lastCallTime){
        lastCallTime = Date.now();
        fps = 0;
        return;
    }
    
    delta = (Date.now() - lastCallTime) / 1000;
    lastCallTime = Date.now();
    fps = Math.floor(1/delta);
}

graphics3d – What is the best way to produce 3d images of tangles and show them on the web so that they can be rotated by the viewer?

On my html5 website on physics, I would like to add computer graphics of tangles, similar to the following photo, and I would like to allow users to rotate the image of a tangle and thus allow viewing the tangle from all sides.

Is this the right forum to ask?

If so, what is the best way to realize this, using Mathematica? (I also have KnotPlot as available tool.)

Any advice would be greatly appreciated.

simple tangle image

html5 – What is the best way to draw 3d images of knots and show them on the web so that they can be rotated by the viewer?

On my html5 website , I would like to make graphics of tangles, similar to the following photo, a charged tangle , and I would like users to allow to rotate it and view it from all sides.

Is this the right forum to ask?

If so, what is the best way to realize this? ( I also have Mathematica and KnotPlot )

Any advice would be greatly appreciated.

windows – Can we keep only X number of files rotated by Y MB with Apache rotatelogs

Can we rotate Apache logs keeping n number of backups rotated by size.

We can rotate apache logs with size by doing following:

ErrorLog “|bin/rotatelogs.exe logs/error_log-%Y-%m-%d.log 20M”

How I can keep only 5 backups always? What I mean is files should be always when it reaches to 20 MB and it should always keep 5 backups.

I am using Apache 2.4.20 on windows.