Game Maker Studio 2 - How to give one input priority over another when controlling the same object? - gml

I'm trying to control an aiming object in a game I'm starting on with two different inputs, one is the left stick so you can aim while moving, and one is the right stick for more precise aim, but I'm having trouble making it so I can control it with the left stick while still moving with the right stick.
I've already tried reordering the code and having a variable to check if the left stick is in use or not, but none of that worked.
if abs(controllerhr) > 0.2 or abs(controllervr) > 0.2{
controllerangle = point_direction(0,0,controllerhr,controllervr)
}
if gamepad_button_check_pressed(0,gp_face3) or gamepad_button_check_pressed(0,gp_shoulderrb) and firingdelay < 0 and ammo > 0{
firingdelay = 4;
ammo -= 1;
oPlayer.hsp-= lengthdir_x(playerrecoil,image_angle);
oPlayer.vsp-= lengthdir_y(playerrecoil,image_angle);
with instance_create_layer(x,y,"Kunai",oKunai){
speed = 15;
direction = other.image_angle;
image_angle = direction;
}
image_angle = controllerangle
}
}
if oPlayer.controller==1 and inuse==0{
if abs(controllerh) > 0.2 or abs(controllerv) > 0.2{
controllerangle = point_direction(0,0,controllerh,controllerv)
}
image_angle = controllerangle
}
P.S. It is indented correctly The indentation just messed up while pasting.
Thanks!

I found a solution, for some reason the shoot controlls were skipping over the code or messing up the ordering or something, so moving the shooting code to the left stick changed the ordering and that fixed it.

Related

How to fix: code not running on certain frames

I have been trying to make my character shoot a projectile on a particular frame of animation. However, sometimes it works and other times it just ignores creating the projectile.
I've tried using alarms instead of checking for the image index but I can't get the timer low enough to get the perfect timing.
I think it may be a problem with the image speed being 0.2 instead of 1.
I'm using a state machine to make it switch between moving and shooting, but I checked and it isn't a problem with state switching over as it changes when I want it to.
Here is relevant code from the shooting state:
if image_index == 2 {
instance_create(x+20*image_xscale,y,obj_projectile);
}
Here is the code that changes the tank over to the shooting state from the main state:
if key_shoot{
state = states.shoot;
image_speed = 0.2;
sprite_index = spr_tankShoot;
}
There is also an animation end event in the object with the following code:
if sprite_index == spr_tankShoot{
state = states.normal;
}
If anyone can see something wrong with the code and/or know what might be going wrong with this, it'd be much appreciated.
I think it may be a problem with the image speed being 0.2 instead of 1.
This is possible - if your animations have different speeds and you don't tend to reset image_index on animation start, you may end up with varying starting indexes (suppose, 0.1) that would not fall right on 2.0 when adding 0.2 to them. Checking that a frame is precisely a number is a not-as-good practice in general though.
You could store image_index at the end of the frame for future reference,
image_index_previous = image_index;
and then check that image_index stepped over 2 since the last frame:
if image_index_previous < 2 && image_index >= 2 {
instance_create(x+20*image_xscale,y,obj_projectile);
}

Faster calculation for large amounts of data / inner loop

So, I am programming a simple Mandelbrot renderer.
My inner loop (which is executed up to ~100,000,000 times each time I draw on screen) looks like this:
Complex position = {re,im};
Complex z = {0.0, 0.0};
uint32_t it = 0;
for (; it < maxIterations; it++)
{
//Square z
double old_re = z.re;
z.re = z.re*z.re - z.im*z.im;
z.im = 2*old_re*z.im;
//Add c
z.re = z.re+position.re;
z.im = z.im+position.im;
//Exit condition (mod(z) > 5)
if (sqrt(z.re*z.re + z.im*z.im) > 5.0f)
break;
}
//Color in the pixel according to value of 'it'
Just some very simple calculations. This takes between 0.5 and a couple of seconds, depending on the zoom and so on, but i need it to be much faster, to enable (almost) smooth scrolling.
My question is: What is my best bet to achieve the maximum possible calculation speed?
OpenCl to use the GPU? Coding it in assembly? Dividing the image into small pieces and dispatch the calculation of each piece on another thread? A combination of those?
Any help is appreciated!
I have written a Mandelbrot set renderer several times... and here are the things that you should keep in mind...
The things that take the longest are the ones that never escape and take all the iterations.
a. so you can make a region in the middle out of a few rectangles and check that first.
any starting point with a real and imaginary part between -1 and 1 will never escape.
you can cache points (20, or 30) in a rolling buffer and if you ever see a point in the buffer that you just calculated means that you have a cycle and it will never escape.
You can use a more general logic that doesn't require a square root... in that if any part is less than -2 or more than 2 it will race out of control and can be considered escaped.
But you can also break this up because each point is its own thing, so you can make a separate thread or gcd dispatch or whatever for each row or quadrant... it is a very easy problem to divide up and run in parallel.
In addition to the comments by #Grady Player you could start just by optimising your code
//Add c
z.re += position.re;
z.im += position.im;
//Exit condition (mod(z) > 5)
if (z.re*z.re + z.im*z.im > 25.0f)
break;
The compiler may optimise the first, but the second will certainly help.
Why are you coding your own complex rather than using complex.h

Generate a random Y for a sprite

I need some help (duh). I want to generate a random Y position for my game in cocos2d.
So the situation goes like this:
The game spawns a platform every 0.2 second. The iPhone / iPad is in landscape mode. Platform appear on the right of the screen (bigger x than width so that the platform appears outside the screen) and starts moving towards the left end of the screen using CCMoveTo.
I pick a random Y for every platform. The problem is that I do not want to spawn a platform on top of another. This means that I need to make a randY which is not "already taken".
The code I've tried so far is this:
//this is a part of code from my addPlatform function. This part in particular cares for the generation of my Y coordinate.
int randY = arc4random() % (int)(3 * (winSize.height/4)); //This prevents to spawn a Y larger than 3/4 of the screen
//here I would like to loop long enough to find a good Y
while (![self isGoodPlatformY:randY])
{
randY = arc4random() % (int)(3 * (winSize.height/4));
}
The next part is my isGoodPlatformY function
- (bool)isGoodPlatformY:(int)platY
{
CGSize winSize = [[CCDirector sharedDirector] winSize];
int padding = 100;
bool ok = true;
for (CCSprite *body in [self children])
{
if (body.tag > platformBody)
{
if (body.position.x < (winSize.width - padding))
{
if (abs(body.position.y - platY) < 20)
{
ok = false;
}
}
}
}
return ok;
}
I loop through all the bodies with larger tag than my platform. I have different types of platform which I separate by using tag. If the body is a platform I first check the X coordinate. If the platform is enough away (padding) I can spawn a new one at that exact point so I check the next one. If not I want to check the Y of that platform. If the Y coordinate is less than 20 pixels in this case I must find a new Y so thats why set the bool to false and return it after the for loop.
I know there is no need for those curly brackets but I was testing some other stuff, thats why I put them there.
This doesn't seem to work. Hope I made myself clear what I want to accomplish. Any help from your side would be much appreciated. Hope I didn't miss something too newbie style :)
I tagged the question in other languages to because this problem could occur "everywhere".
Assuming that all the spawned platforms have the same tag as you mentioned that you are using tags to separate different types of platforms.
All previous platforms will not return true for this line
if (body.tag > platformBody)
because they all have the same tag, you will compare (1 > 1) which is false.
Therefore your method will always return YES (which is your default value for ok) and will never check to see if the platforms collide with each other.
I recommend stepping through the method to see if this is the case.
Now I have discovered that I can answer my own questions :) (silly me). So yeah, the problem was fixed a long time ago but to anyone who might be reading this, the solution was to change the line:
if (body.position.x < (winSize.width - padding))
To:
if (body.position.x > (winSize.width - padding))

iOS Pong Development, Collision Detection

I am in a late phase of finishing my first usable iOS app.
I am creating a simple Pong game i am using a simple collision detection using CGRectIntersectsRect, but i came up with a problem.
if(CGRectIntersectsRect(mic.frame,plosina_a.frame)) {
if(mic.center.y < (plosina_a.center.y + plosina_a.frame.size.height)) {
RychlostMice.y = -RychlostMice.y;
}
}
if(CGRectIntersectsRect(mic.frame,plosina_b.frame)) {
if(mic.center.y < (plosina_b.center.y + plosina_b.frame.size.height)) {
RychlostMice.y = -RychlostMice.y;
}
}
When i use it like this the ball (mic) sort of gets to the paddles (plosina) and starts moving the other way sort of in the middle of the paddle.
My programming teacher managed to fix this problem for one of the paddles (the _b one) by adding the .frame.size.height instead of just .frame which i have used before, but when i did the same thing for the other paddle it didn't work i don't know what's up with that.
Also it creates another problem sometimes there is a situation where the ball get's caught up in the paddle - so I'm looking for a definition of the whole object and not just one side probably?
i hope you can help.
I can see three potential problems here.
The first is that you are waiting until the ball overlaps the paddle before counting it as a touch. It sounds like you really want to start the ball moving in the other direction when the ball touches the paddle, not when it intersects it. The CGRectIntersectsRect waits until they overlap before returning true. If you make either rectangle one pixel larger with a call to CGRectInset, your test will return true as soon as the ball reaches that paddle--by that time, there will be one pixel overlapping the expand rectangle. The test would look like this:
if(CGRectIntersectsRect(CGRectInset(mic.frame, -1, -1),plosina_a.frame)) {
if(mic.center.y < (plosina_a.center.y + plosina_a.frame.size.height)) {
RychlostMice.y = -RychlostMice.y;
}
}
if(CGRectIntersectsRect(CGRectInset(mic.frame, -1, -1),plosina_b.frame)) {
if(mic.center.y < (plosina_b.center.y + plosina_b.frame.size.height)) {
RychlostMice.y = -RychlostMice.y;
}
}
The second potential problem has to do with the velocity of the ball. Without seeing all of the code, I don't know if this is a problem or not. If the ball can move more than one pixel at a time, it could easily overlap--or even pass through--the paddle without a hit detection. There are lots of logic changes you can add to take care of this, but the easiest solution may be to just make sure the ball doesn't move more than one pixel at a time.
Finally, if you want to use the hack for both paddles, reverse the sign of the comparison on the other side of the game.
I'm guessing that your pong is played vertically, so that one paddle is at the top of the screen and the other is at the bottom?
If you you need to mirror the logic vertically for the other paddle. Right now you are using the same logic for the top and bottom paddles, but for the bottom paddle you probably need something like the following instead
if(CGRectIntersectsRect(mic.frame,plosina_b.frame)) {
if(mic.center.y > (plosina_b.center.y - plosina_b.frame.size.height)) {
RychlostMice.y = -RychlostMice.y;
}
}
Notice how I'm using the > sign and subtracting the height instead of adding it.

Bouncing ball not conforming to Conservation of Energy Rule

I am currently busy on writing a small ball physics engine for my programming course in Win32 API and c++. I have finished the GDI backbuffer renderer and the whole GUI (couple of more things to adjust) but i am very near to completion. The only big obstacles that last are ball to ball collision (but i can fix this on my own) but the biggest problem of them all is the bouncing of the balls. What happens is that i throw a ball and it really falls, but once it bounces it will bounce higher than the point were i released it??? the funny thing is, it only happens if below a certain height. This part is the physics code:
(If you need any more code or explanation, please ask, but i would greatly appreciate it if you guys could have a look at my code.)
#void RunPhysics(OPTIONS &o, vector<BALL*> &b)
{
UINT simspeed = o.iSimSpeed;
DOUBLE DT; //Delta T
BOOL bounce; //for playing sound
DT= 1/o.REFRESH;
for(UINT i=0; i<b.size(); i++)
{
for(UINT k=0; k<simspeed; k++)
{
bounce=false;
//handle the X bounce
if( b.at(i)->rBall.left <= 0 && b.at(i)->dVelocityX < 0 ) //ball bounces against the left wall
{
b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof;
bounce=true;
}
else if( b.at(i)->rBall.right >= SCREEN_WIDTH && b.at(i)->dVelocityX > 0) //ball bounces against the right wall
{
b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof;
bounce=true;
}
//handle the Y bounce
if( b.at(i)->rBall.bottom >= SCREEN_HEIGHT && b.at(i)->dVelocityY > 0 ) //ball bounces against the left wall
{
//damping of the ball
if(b.at(i)->dVelocityY < 2+o.dGravity/o.REFRESH)
{
b.at(i)->dVelocityY = 0;
}
//decrease the Velocity of the ball according to the bouncecof
b.at(i)->dVelocityY = b.at(i)->dVelocityY * -1*b.at(i)->dBounceCof;
b.at(i)->dVelocityX = b.at(i)->dVelocityX * b.at(i)->dBounceCof;
bounce=true;
}
//gravity
b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH;
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
//METER IS DEFINED GLOBALLY AS 100 which is the amount of pixels in a meter
b.at(i)->pOrigin.x += b.at(i)->dVelocityX/o.REFRESH*METER;
b.at(i)->UpdateRect();
}
}
return;
}
You are using the Euler method of integration. It is possible that your time step (DT) is too large. Also there seems to be a mistake on the row that updates the Y coordinate:
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
You have already added the gravity to the velocity, so you don't need to add it to the position and you are not multiplying the velocity by DT. It should be like this:
b.at(i)->pOrigin.y += b.at(i)->dVelocityY * DT;
Furthermore there appears to be some confusion regarding the units (the way METER is used).
Okay, a few things here.
You have differing code paths for bounce against left wall and against right wall, but the code is the same. Combine those code paths, since the code is the same.
As to your basic problem: I suspect that your problem stems from the fact that you apply the gravity after you apply any damping forces / bounce forces.
When do you call RunPhysics? In a timer loop? This code is just an approximation and no exact calculation. In the short interval of delta t, the ball has already changed his position and velocity a litte bit which isn't considered in your algorithm and produces little mistakes. You'll have to compute the time until the ball hits the ground and predict the changes.
And the gravity is already included in the velocity, so don't add it twice here:
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
By the way: Save b.at(i) in a temporary variable, so you don't have to recompute it in every line.
Ball* CurrentBall = b.at(i);
ANSWER!!ANSWER!!ANSWER!! but i forgot my other account so i can't flag it :-(
Thanks for all the great replies, it really helped me alot! The answers that you gave were indeed correct, a couple of my formulas were wrong and some code optimisation could be done, but none was really a solution to the problem. So i just sat down with a piece of paper and started calculation every value i got from my program by hand, took me like two hours :O But i did find the solution to my problem:
The problem is that as i update my velocity (whith corrected code) i get a decimal value, no problem at all. Later i increase the position in Y by adding the velocity times the Delta T, which is a verry small value. The result is a verry small value that needs to be added. The problem is now that if you draw a Elipse() in Win32 the point is a LONG and so all the decimal values are lost. That means that only after a verry long period, when the values velocity starts to come out of the decimal values something happens, and that alongside with that, the higher you drop the ball the better the results (one of my symptons) The solution to this problem was really simple, ad an extra DOUBLE value to my Ball class which contained the true position (including decimals) of my ball. During the RenderFrame() you just take the floor or ceiling value of the double to draw the elipse but for all the calculations you use the Double value. Once again thanks alot for all your replies, STACKOVERFLOW PEOPLE ROCK!!!
If your dBounceCof is > 1 then, yes your ball will bounce higher.
We do not have all the values to be able to reply to your question.
I don't think your equation for position is right:
b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH;
This is v=v0+gt - that seems fine, although I'd write dGravity*DT instead of dGravity/REFRESH_FREQ.
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
But this seems off: It is eqivalent to p = p0+v + 1/2gt^2.
You ought to multiply velocity * time to get the units right
You are scaling the gravity term by pixels/meter, but not the velocity term. So that ought to be multiplied by METER also
You have already accounted for the effect of gravity when you updated velocity, so you don't need to add the gravity term again.
Thanks for the quick replies!!! Sorry, i should have been more clear, the RunPhysics is beiing run after a PeekMessage. I have also added a frame limiter which makes sure that no more calculations are done per second than the refresh rate of the monitor. My dleta t is therefore 1 second devided by the refresh rate. Maybe my DT is actually too small to calculate, although it's a double value??? My cof of restitution is adjustable but starts at 0.9
You need to recompute your position on bounce, to make sure you bounce from the correct place on the wall.
I.e. resolve the exact point in time when the bounce occured, and calculate new velocity/position based on that direction change (partially into a "frame" of calculation) to make sure your ball does not move "beyond" the walls, more and more on each bounce.
W.r.t. time step, you might want to check out my answer here.
In a rigid body simulation, you need to run the integration up to the instant of collision, then adjust the velocities to avoid penetration at the collision, and then resume the integration. It's sort of an instantaneous kludge to cover the fact that rigid bodies are an approximation. (A real ball deforms during a collision. That's hard to model, and it's unnecessary for most purposes.)
You're combining these two steps (integrating the forces and resolving the collisions). For a simple simulation like you've shown, it's probably enough to skip the gravity bit on any iteration where you've handled a vertical bounce.
In a more advanced simulation, you'd split any interval (dt) that contains a collision at the actual instance of collision. Integrate up to the collision, then resolve the collision (by adjusting the velocity), and then integrate for the rest of the interval. But this looks like overkill for your situation.