I'm currently implementing mouse input using Raw input.
The disadvantage though is, that pointer ballistic is not included. Unfortunately microsoft's website dealing with this topic is not online any more. Furthermore I can't find a function retrieving the pointer acceleration set in windows (maybe I'm too stupid).
How do I get the acceleration and how do I use it to calculate the new intuitive cursor position out of the raw x and y offset?
EDIT:
So concerning the documentation IInspectable posted in his comment, the code for calculating the acceleration would be:
long xPos = raw->data.mouse.lLastX;
long yPos = raw->data.mouse.lLastY;
int speed;
int acceleration[3];
SystemParametersInfo(SPI_GETMOUSESPEED, 0, &speed, 0);
SystemParametersInfo(SPI_GETMOUSE, 0, acceleration, 0);
if (acceleration[2] > 0 && acceleration[0] < abs(raw->data.mouse.lLastX))
xPos *= 2;
else if (acceleration[2] > 1 && acceleration[1] < abs(raw->data.mouse.lLastX))
xPos *= 2;
if (acceleration[2] > 0 && acceleration[0] < abs(raw->data.mouse.lLastX))
yPos *= 2;
else if (acceleration[2] > 1 && acceleration[1] < abs(raw->data.mouse.lLastX))
yPos *= 2;
xPos *= round((float)speed / 10.0f);
yPos *= round((float)speed / 10.0f);
Am I right, is this how to add acceleration to the raw mouse input?
Strange is, that when I retrieve acceleration with SystemParametersInfo and SPI_GETMOUSE the values stay at {6, 10, 1} even if I change the pointer acceleration in windows.
I have a single function that does this scaling, for an arbitrary delta (dq), and it is similar to yours. However, my experience is that Windows acceleration and pointer enhancement, in particular when there's DPI awareness to take into account, makes the mapping between RAWINPUT and what a corresponding WM_MOUSEMOVE would see, very tricky...
int ApplyMouseAcceleration(int dq)
{
auto absdq{ abs(dq) };
// based on https://msdn.microsoft.com/en-us/library/windows/desktop/ms646260(v=vs.85).aspx
if (MouseAccelerationparams[0] && absdq > MouseAccelerationparams[0])
{
dq *= 2;
if ((absdq > MouseAccelerationparams[1]) && (MouseAccelerationparams[2] == 2))
{
dq *= 2;
}
}
dq = (dq*MouseSpeed) / 10;
return dq;
}
Related
I'm trying to make a game and I'm stuck on random level design. Basically, I'm trying to create a line from one edge/corner to another edge/corner while having some randomness to it.
See below image 1 [link broken] and 2 for examples. I'm doing this in processing and every attempt I've tried hasn't yielded proper results. I can get them to populate randomly but not in a line or from edge to edge. I'm trying to do this on a 16 x 16 grid by the way. Any ideas or help would be greatly appreciated thanks!
Image 2:
Based on your description, the challenge is in having a connected line from top to bottom with a bit of randomness driving left/right direction.
There are multiple options.
Here's a basic idea that comes to mind:
pick a starting x position: left's say right down the middle
for each row from 0 to 15 (for 16 px level)
pick a random between 3 numbers:
if it's the 1st go left (x decrements)
if it's the 2nd go right (x increments)
if it's the 3rd: ignore: it means the line will go straight down for this iteration
Here's a basic sketch that illustrates this using PImage to visualise the data:
void setup(){
size(160, 160);
noSmooth();
int levelSize = 16;
PImage level = createImage(levelSize, levelSize, RGB);
level.loadPixels();
java.util.Arrays.fill(level.pixels, color(255));
int x = levelSize / 2;
for(int y = 0 ; y < levelSize; y++){
int randomDirection = (int)random(3);
if(randomDirection == 1) x--;
if(randomDirection == 2) x++;
// if randomDirection is 0 ignore as we don't change x -> just go down
// constrain to valid pixel
x = constrain(x, 0, levelSize - 1);
// render dot
level.pixels[x + y * levelSize] = color(0);
}
level.updatePixels();
// render result;
image(level, 0, 0, width, height);
fill(127);
text("click to reset", 10, 15);
}
// hacky reset
void draw(){}
void mousePressed(){
setup();
}
The logic is be pretty plain above, but free to replace random(3) with other options (perhaps throwing dice to determine direction or exploring other psuedo-random number generators (PRNGs) such as randomGaussian(), noise() (and related functions), etc.)
Here's a p5.js version of the above:
let levelSize = 16;
let numBlocks = levelSize * levelSize;
let level = new Array(numBlocks);
function setup() {
createCanvas(320, 320);
level.fill(0);
let x = floor(levelSize / 2);
for(let y = 0 ; y < levelSize; y++){
let randomDirection = floor(random(3));
if(randomDirection === 1) x--;
if(randomDirection === 2) x++;
// if randomDirection is 0 ignore as we don't change x -> just go down
// constrain to valid pixel
x = constrain(x, 0, levelSize - 1);
// render dot
level[x + y * levelSize] = 1;
}
// optional: print to console
// prettyPrintLevel(level, levelSize, numBlocks);
}
function draw() {
background(255);
// visualise
for(let i = 0 ; i < numBlocks; i++){
let x = i % levelSize;
let y = floor(i / levelSize);
fill(level[i] == 1 ? color(0) : color(255));
rect(x * 20, y * 20, 20, 20);
}
}
function prettyPrintLevel(level, levelSize, numBlocks){
for(let i = 0; i < numBlocks; i+= levelSize){
print(level.slice(i, i + levelSize));
}
}
function mousePressed(){
setup();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
The data is a structured a 1D array in both examples, however, if it makes it easier it could easily be a 2D array. At this stage of development, whatever is the simplest, most readable option is the way to go.
i have a task to make a pattern of circles and squares as described on photo, and i need to animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated. i tried but i cant understand problem
{
size(500,500);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a, int b)
{
boolean isShrinking = false;
for(int x = 0; x <= width; x += a){
for(int y = 0; y <= height; y += a){
stroke(#1B08FF);
ellipse(x,y,a,a);
stroke(#FF0000);
rect(x,y,a,a);
stroke(#0BFF00);
ellipse(x+25,y+25,a/2,a/2);
if (isShrinking){a -= b;}
else {a += b;}
if (a == 50 || a == 200){
isShrinking = !isShrinking ; }
}
}
}
void draw()
{
pattern(50,1);
}
this is what pattern need to look like
Great that you've posted your attempt.
From what you presented I can't understand the problem either. If this is an assignment, perhaps try to get more clarifications ?
If you comment you the isShrinking part of the code indeed you have an drawing similar to image you posted.
animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated
Does that simply mean scaling the whole pattern ?
If so, you can make use of the sine function (sin()) and the map() function to achieve that:
sin(), as the reference mentions, returns a value between -1 and 1 when you pass it an angle between 0 and 2 * PI (because in Processing trig. functions use radians not degrees for angles)
You can use frameCount divided by a fractional value to mimic an even increasing angle. (Even if you go around the circle multiple times (angle > 2 * PI), sin() will still return a value between -1 and 1)
map() takes a single value from one number range and maps it to another. (In your case from sin()'s result (-1,1) to the scale range (1,4)
Here's a tweaked version of your code with the above notes:
void setup()
{
size(500, 500, FX2D);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a)
{
for (int x = 0; x <= width; x += a) {
for (int y = 0; y <= height; y += a) {
stroke(#1B08FF);
ellipse(x, y, a, a);
stroke(#FF0000);
rect(x, y, a, a);
stroke(#0BFF00);
ellipse(x+25, y+25, a/2, a/2);
}
}
}
void draw()
{
// clear frame (previous drawings)
background(255);
// use the frame number as if it's an angle
float angleInRadians = frameCount * .01;
// map the sin of the frame based angle to the scale range
float sinAsScale = map(sin(angleInRadians), -1, 1, 1, 4);
// apply the scale
scale(sinAsScale);
// render the pattern (at current scale)
pattern(50);
}
(I've chosen the FX2D renderer because it's smoother in this case.
Additionally I advise in the future formatting the code. It makes it so much easier to read and it barely takes any effort (press Ctrl+T). On the long run you'll read code more than you'll write it, especially on large programs and heaving code that's easy to read will save you plenty of time and potentially headaches.)
I would like to make a simple animation of the character rotating itself when it jumps. I'm making an indie platformer so this should be simple to do, I think, but I'm too newbie for this.
Here's the movement code.
//------------------------- MOVEMENT INPUT
xMove = kRight - kLeft;
xSpd = xMove * mSpd;
ySpd += 0.65;
//------------------------- JUMP
onGround = place_meeting(x,y+1,oSolid);
if(onGround) airJump = 1;
if(kJump){
if(onGround or airJump > 0){
ySpd = -12;
airJump = 0;
}
}
//------------------------- FINAL MOVEMENT
if(place_meeting(x + xSpd, y, oSolid)){
while(!place_meeting(x + sign(xSpd), y, oSolid)) x += sign(xSpd);
xSpd = 0;
}
if(place_meeting(x + xSpd, y + ySpd, oSolid)){
while(!place_meeting(x + xSpd, y + sign(ySpd), oSolid)) y += sign(ySpd);
ySpd = 0;
}
x += xSpd;
y += ySpd;
if xSpd < 0 dir = -1;
if xSpd > 0 dir = 1;
The player is a simple square, so I would like to make it rotate 360 degrees while on the air.
You should be able to use image_angle for this, changing the value will change the angle of the sprite, and continiously increasing/decreasing that value will simulate a rotation.
However, keep in mind that if you rotate the sprite, the hitbox of the sprite will rotate as well. You can probably set the hitbox apart from the sprite so it won't interrupt with each other.
Example:
https://manual.yoyogames.com/GameMaker_Language/GML_Reference/Asset_Management/Sprites/Sprite_Instance_Variables/image_angle.htm
For player movement collision handling you want to avoid using image_angle variable by using your own variable for the image rotation with the draw_sprite_ext function. Also by change you end up wanting to use the image angle for anything its good to wrap it mostly later if your trying to use fov and what not.
For example
function Scr_Player_Create(){
image_offset = 0;
}
function Scr_Player_Step(){
image_offset += (keyboard_check(vk_right) - keyboard_check(vk_left)) * 10;
image_offset = wrap(image_offset, 0, 359);
}
function Scr_Player_Draw(){
draw_sprite_ext( sprite_index, image_index, x, y, image_xscale, image_yscale,
image_angle + image_offset, image_blend, image_alpha );
draw_text(10, 10, image_offset);
}
function wrap(wrap_value, wrap_minimum, wrap_maximum){
// Credit: Juju from GMLscripts forums!
var _mod = ( wrap_value - wrap_minimum ) mod ( wrap_maximum - wrap_minimum );
if ( _mod < 0 ) return _mod + wrap_maximum else return _mod + wrap_minimum;
}
Another approach you could do to avoid image_angle effecting your collision is this
var _angle = image_angle;
image_angle += image_offset;
draw_self();
image_angle = _angle;
How does one constrain interactively drawing a line to 45degrees?
Imagine there in an underlining grid that's at 45 degees which the mouse draw is magnetized too. Perhaps on mousedown decides which your starting position is and after that your Mouse.X and Mouse.Y position only update in 45 degrees from that starting click?
float dif = 10;
float easing = 0.05;
boolean current = false;
boolean started = false;
float rainbow, x, y;
float colbase;
PVector pos, prev_pos, update_pos;
float step = 25;
void setup(){
size(400, 400);
background(100);
colorMode(HSB);
}
void draw(){
if (rainbow >= 255) rainbow=0; else rainbow+=5;
if (frameCount % dif == 0) {
colbase = rainbow;
}
if(mousePressed){
update_pos();
if(current){
started = true;//start drawing
pos = update_pos;
}else{
prev_pos = update_pos;
}
current = !current;
}else{
update_pos();
started = false;
pos = update_pos;
prev_pos = update_pos;
}
if(started){
//style for lines
strokeWeight(step);
stroke(colbase,255,255);
noFill();
line(prev_pos.x, prev_pos.y, pos.x, pos.y);
}
}
PVector update_pos(){
x = lerp(x, mouseX, easing);
y = lerp(y, mouseY, easing);
update_pos = new PVector(x, y);
return update_pos;
}
I would like to say that I like this. Also, that this question was ultimately way harder to answer than I though it would be.
Here's the result:
First, I took the liberty to reorganize your example code. I don't know how experienced you are, and maybe some of the things I changed were on purpose, but it seemed to me that your example had a lot of weird code bits dangling. Here's the example code with my changes (check the next code block for the answer, this one is more like a code review to help you in general):
float dif = 10;
float easing = 0.05;
boolean current, started; // automatically initializing as false unless stated otherwise
float rainbow;
float colbase;
PVector pos, prev_pos;
float step = 25;
void setup() {
size(400, 400);
background(100);
colorMode(HSB); // clever!
pos = prev_pos = new PVector(); // instanciating some non-null PVectors
}
void draw() {
pos = prev_pos = update_pos(); // cascade attribution: it starts by the last one and goes back toward 'pos'
if (mousePressed) {
if (!started) {
// initializing variables needed for drawing
started = true;
pos = prev_pos = new PVector(mouseX, mouseY);
}
} else {
started = false;
}
if (started) {
updateColor();
strokeWeight(step);
stroke(colbase, 255, 255);
noFill();
line(prev_pos.x, prev_pos.y, pos.x, pos.y);
}
}
void updateColor() {
if (rainbow >= 255) {
rainbow=0;
} else {
rainbow+=5;
}
if (frameCount % dif == 0) {
colbase = rainbow;
}
}
PVector update_pos() {
float x = lerp(pos.x, mouseX, easing);
float y = lerp(pos.y, mouseY, easing);
return new PVector(x, y);
}
Notice how I changed a couple variables names. As a general rule, you should always name your variables as if the guy maintaining your code was an angry biker who knows where you live.
Now to solve your actual question:
boolean isDrawing;
float rainbow, colbase, dif, easing, step, centerZone;
PVector pos, prev_pos, origin, quadrant;
void setup() {
size(400, 400);
background(100);
colorMode(HSB); // clever!
centerZone = 5; // determine how close to the original click you must be to change quadrant
dif = 10;
easing = 0.05;
step = 25;
origin = pos = prev_pos = new PVector();
}
void draw() {
updatePosition();
if (mousePressed) {
if (!isDrawing) {
// setting variables needed for drawing
isDrawing = true;
origin = pos = prev_pos = new PVector(mouseX, mouseY); // drawing should always start where the mouse currently is
}
} else {
isDrawing = false;
}
if (isDrawing) {
updateColor();
strokeWeight(step);
stroke(colbase, 255, 255);
noFill();
line(prev_pos.x, prev_pos.y, pos.x, pos.y);
}
}
void updateColor() {
if (rainbow >= 255) {
rainbow=0;
} else {
rainbow+=5;
}
if (frameCount % dif == 0) {
colbase = rainbow;
}
}
void updatePosition() {
float relativeX = pos.x - origin.x;
float relativeY = pos.y - origin.y;
float diffX = mouseX - origin.x;
float diffY = mouseY - origin.y;
float distance = abs(diffX) > abs(diffY) ? abs(diffX) : abs(diffY); // this is just inline if, the syntax being " condition ? return if true : return if false; "
prev_pos = pos;
// validating if the mouse is in the same quadrant as the pencil
PVector mouseQuadrant = new PVector(diffX > 0 ? 1 : -1, diffY > 0 ? 1 : -1);
// we can only change quadrant when near the center
float distanceFromTheCenter = abs(relativeX) + abs(relativeY);
if (quadrant == null || distanceFromTheCenter < centerZone) {
quadrant = new PVector(diffX > 0 ? 1 : -1, diffY > 0 ? 1 : -1);
}
// if the mouse left it's quadrant, then draw toward the center until close enough to change direction
// ^ is the XOR operator, which returns true only when one of the sides is different than the other (one true, one false)
// if the quadrant info is positive and the diff coordinate is negative (or the other way around) we know the mouse has changed quadrant
if (distanceFromTheCenter > centerZone && (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0)) {
// going toward origin
pos = new PVector(lerp(prev_pos.x, origin.x, easing), lerp(prev_pos.y, origin.y, easing));
} else {
// drawing normally
pos = new PVector(lerp(prev_pos.x, origin.x + (distance * quadrant.x), easing), lerp(prev_pos.y, origin.y + (distance * quadrant.y), easing));
}
}
I'll answer your questions on this code if you have any. Have fun!
EDIT:
This part could use more explainations, so let's elaborate a little bit:
if (distanceFromTheCenter > centerZone && (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0)) {
// going toward origin
} else {
// drawing normally
}
The point of this check is to know if the mouse is still in the same quadrant than the "pencil", by which I mean the point where we're drawing.
But what are the "quadrants"? Remember, the user can only draw in 45 degrees lines. Theses lines are defines in relation to the point where the user clicked to draw, which I call "origin":
Which means that the screen is always divided into 4 different "quadrants". Why? Because there is 4 different directions where we can draw. But we don't want the user to have to stick to these exact pixels to be able to draw, do we? We could, but that's not how the algo is working: it poses a pencil on the page and then follows the mouse. So here if the mouse goes up-left from origin, the pencil will draw on the up-left branch of the 45 degrees X lines. Each of these imaginary lines has it's own "part of the screen" where they control where the pencil has the right to draw, which I call "quadrants":
Now with this algorithm we can force the pencil over the 45 degrees lines, but what happens if the mouse goes from one quadrant to another one? I figured out that the pencil should follow, but without breaking the "only drawing in 45 degrees lines" rule, so it has to go through the center before changing quadrant:
There is no big secret here. It's kind of easy to figure the business rules we want to apply:
While the mouse and the pencil are in the same quadrant, follow the mouse's position to draw (but only on the line).
If the mouse is in a different quadrant from the pencil, draw toward the center, then toward the mouse normally.
Which is exactly what we're doing here:
if (mouse and pencil are in different quadrants) {
// draw toward origin
} else {
// draw toward the mouse
}
Then... if it's so simple, why this convoluted code?
(distanceFromTheCenter > centerZone && (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0))
Well, really, it could be written in a waaay easier to read way, but it would be longer. Let's decompose it and see why it's written this way:
My operational logic here go as follow:
As you probably know, point (0,0) is on the upper-left side of the sketch. Most drawing in computer science calculate coordinates this way.
Quadrants exist in relation to the origin point (where the user clicked to start drawing).
Relative coordinates in each quadrant will be either positive or negative. X will be positive if they are to the right of origin. Y will be positive if they are lower in the screen than origin:
If you follow my logic, when relative coordinate of the mouse and pencil aren't both positive or both negative in the same way, it would mean that they are not located in the same quadrant.
So:
distanceFromTheCenter > centerZone => when we're close enough to the center, we can let the pencil switch direction. No need to calculate the rest if the pencil isn't near the center.
relativeX > 0 ^ mouseQuadrant.x > 0 => relativeX is really just pos.x - origin.x. It's where the pencil is in relation to origin. mouseQuadrant "knows" where the mouse is in relation to the origin (it's just diffX and diffY as interpreted for later use, in fact we totally could have used diffX and diffY instead as we just compare if they are positive or negative numbers)
Why the XOR operator if it's so simple? Because of this:
relativeX > 0 ^ mouseQuadrant.x > 0
// is the same thing than this pseudocode:
if (relativeX sign is different than mousequadrant.x's sign)
// and the same thing than this more elaborated code:
!(relativeX > 0 && mouseQuadrant.x > 0) || !(relativeX < 0 && mouseQuadrant.x < 0)
// or, in a better writing:
(relativeX > 0 && mouseQuadrant.x < 0) || (relativeX < 0 && mouseQuadrant.x > 0)
...which is also convoluted and also ugly. So, really, (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0) is just a short hand for:
(!(relativeX > 0 && mouseQuadrant.x > 0) || !(relativeX < 0 && mouseQuadrant.x < 0) || !(relativeY > 0 && mouseQuadrant.y > 0) || !(relativeY < 0 && mouseQuadrant.y < 0))
I hope this just made sense! Have fun!
I experienced that MTLBuffers with computionally intensive shader functions tend to stop calculating before all threadgroups are done. When I use a MTLComputePipelineState and MTLComputeCommandEncoder to blur an image with very large blur radii the resulting image half way processed and one can actually see half finished threadgroups. I did not narrow it down to the exact amount of blur radius, but 16 pixels works fine, 32 is already too much and not even half the groups are computed.
So are there any limitations on how long a shader function call should take to finish or anything like that? I just finished most of the documentation about how to use the Metal framework and I cannot recall stumbling upon any such statements.
EDIT
Since in my case the problem was not a simple timeout but some internal error I'm going to add some code.
The most expensive part of is the block-matching algorithm that finds matching blocks in two images (i.e consecutive frames in a movie)
//Exhaustive Search Block-matching algorithm
kernel void naiveMotion(
texture2d<float,access::read> inputImage1 [[ texture(0) ]],
texture2d<float,access::read> inputImage2 [[ texture(1) ]],
texture2d<float,access::write> outputImage [[ texture(2) ]],
uint2 gid [[ thread_position_in_grid ]]
)
{
//area to search for matches
float searchSize = 10.0;
int searchRadius = searchSize/2;
//window size to search in
int kernelSize = 6;
int kernelRadius = kernelSize/2;
//this will store the motion direction
float2 vector = float2(0.0,0.0);
float2 maxVector = float2(searchSize,searchSize/2);
float maxVectorLength = length(maxVector);
//maximum error caused by noise
float error = kernelSize*kernelSize*(10.0/255.0);
for (int y = -searchRadius; y < searchRadius; ++y)
{
for (int x = 0; x < searchSize; ++x)
{
float diff = 0;
for (int b = - kernelRadius; b < kernelRadius; ++b)
{
for (int a = - kernelRadius; a < kernelRadius; ++a)
{
uint2 textureIndex(gid.x + x + a, gid.y + y + b);
float4 targetColor = inputImage2.read(textureIndex).rgba;
float4 referenceColor = inputImage1.read(gid).rgba;
float targetGray = 0.299*targetColor.r + 0.587*targetColor.g + 0.114*targetColor.b;
float referenceGray = 0.299*referenceColor.r + 0.587*referenceColor.g + 0.114*referenceColor.b;
diff = diff + abs(targetGray - referenceGray);
}
}
if ( error > diff )
{
error = diff;
//vertical motion is rather irrelevant but negative values can't be stored so just take the absolute value
vector = float2(x, abs(y));
}
}
}
float intensity = length(vector)/maxVectorLength;
outputImage.write(float4(normalize(vector), intensity, 1),gid);
}
I am using that shader on a 960x540px image. With a searchSize of 9 and kernelSize of 8 the shader runs over the whole image. Changing the searchSize to 10 and the shader will stop early with an error code 1.