Order of calling methods - why does it matter in this example? - c#

I have the following method, called in my update loop, to check if one of two buttons has been pressed.
private void CheckInputs()
{
if (CheckButton(startNewGameButtonTexture, startNewGameButtonPosition))
{
//break 1 is here
}
if (CheckButton(continueCareerButtonTexture, continueCareerButtonPosition))
{
//break 2 is here
}
}
Buttons are just rectangles, and if the mouse is over them, and the click is released the CheckButton bool returns true:
public bool CheckButton(Texture2D texture, Vector2 vector)
{
MouseState CurrentMouseState = Mouse.GetState();
bool outcome;
if (CurrentMouseState.X > vector.X && CurrentMouseState.X < vector.X + texture.Width &&
CurrentMouseState.Y > vector.Y && CurrentMouseState.Y < vector.Y + texture.Height)
{
if (CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState == ButtonState.Pressed)
{
outcome = true;
}
else
{
outcome = false;
}
}
else
{
outcome = false;
}
PreviousMouseState = CurrentMouseState.LeftButton;
return outcome;
}
In the current order, the startNewGameButton works (ie debugging stops at break 1), but the continueCareerButton doesn't work (clicking on the button does not trigger break 2).
But if I change the order of the the checks to this:
private void CheckInputs()
{
if (CheckButton(continueCareerButtonTexture, continueCareerButtonPosition))
{
//break 2 is here
}
if (CheckButton(startNewGameButtonTexture, startNewGameButtonPosition))
{
//break 1 is here
}
}
the continueCareerButton now works (break 2), but the startNewGameButton now doesn't (break 1).
I think the mouse states must not be working properly, but I can't work out why.

You are setting your PreviousMouseState every time you check.
You should be setting it once per frame, the simplest way to do this is inside the Update() function:
void Update(..) {
CurrentMouseState := Mouse.GetState()
// code...
PreviousMouseState = CurrentMouseState
}
Otherwise it will only ever work for the first call of your CheckButton() function instead of every call.

As soon as the button is released, you are setting PreviousMouseState to ButtonState.Released in the first call to CheckButton. Thus the second call to CheckButton can never return true (because PreviousMouseState is almost always equal to CurrentMouseState.LeftButton). Don't set PreviousMouseState until after both if statements.

Related

How to make my character play after clicking a button, then bots auto play?

I am creating this simple 3D game but I'm having an issue with player vs computer mode. I want to be able to play vs 1 to 3 bots and when it's my turn I want the game to wait for me to click, but when it's the bots turn I want to them to auto play. What really happens with my code is that everything goes to auto play. I know the issue is with Update function because Update is called once per frame but I don't know how to fix it. Can you help me? The idea is to use a tracker/counter like i = 0 first. When it's 0 it means my character will play so it should wait for my mouse to be pressed. When it's not 0 it will be bots turn. This is the section of the code. Function veprimetELojtareve is the same as the code inside if(!bota).
private int i = 0;
// Update is called once per frame
void Update()
{
if (!bota)
{
if (Input.GetMouseButtonDown(0)) // Left Click
{
if (hasLanded)
Reset();
RollDice();
}
if (rb.IsSleeping() && !hasLanded && thrown)
{
hasLanded = true;
rb.useGravity = false;
rb.isKinematic = true;
SideValueCheck();
}
else if (rb.IsSleeping() && hasLanded && diceValue == 0)
RollAgain();
}
else
{
if (i == 0)
veprimetELojtareve();
else
{
if (hasLanded)
Reset();
RollDice();
if (rb.IsSleeping() && !hasLanded && thrown)
{
hasLanded = true;
rb.useGravity = false;
rb.isKinematic = true;
SideValueCheck();
}
else if (rb.IsSleeping() && hasLanded && diceValue == 0)
RollAgain();
}
i = (i + 1) % numriLojtareve;
Debug.Log("Vlera e i eshte: " + i);
}
}

How to enable boolean one after another when some time has passed?

I have 4 "mana balls". They are 4 individual game objects. After player casted a spell, one magic ball is spent and so on until he has spent all 4 magic balls. I want to develop a recharging system. When player casted a spell and first mana ball was spent, it needs to recharge again after 10 sec. If he casted again, second mana ball was spent and first cancels its recharging, and recharging of second mana ball began. After 10 seconds, second mana ball has recharged, and then begins next 10 seconds of first mana ball recharging.
I have code for spending mana balls:
private void ManaBall()
{
if(finishMagic == true && manaball4 == false && manaball3 == false)
{
manaBall4.SetActive(false); // Mana ball sprite is deactivated
manaball4 = true; // Boolean to confirm this mana ball was deactivated (for Ifs)
manaBallEmpty4.SetActive(true); // Empty space sprite instead of mana ball is activated
}
else if (finishMagic == true && manaball4 == true && manaball3 == false)
{
manaBall3.SetActive(false);
manaball3 = true;
manaBallEmpty3.SetActive(true);
}
}
I have reversed code for recharging mana balls:
private void ManaReload()
{
if (manaball4 == true && manaball3 == false)
{
manaBallEmpty4.SetActive(false);
manaball4 = false;
manaBall4.SetActive(true);
}
else if (manaball4 == true && manaball3 == true)
{
manaBallEmpty3.SetActive(false);
manaball3 = false;
manaBall3.SetActive(true);
}
I've tried creating coroutine which checks if any mana balls were spent after player casted a spell, and if it was, it started recharging it. But everytime I casted a spell, that function would start, giving shorter intervals than 10 seconds in between.
I need some advice where or how to put recharging function in code.
Coroutine I've tried:
IEnumerator FinishSpellAttack()
{
finishMagic = true;
ManaBall();
yield return new WaitForSeconds(1f);
finishMagic = false;
yield return new WaitForSeconds(10f);
ManaReload();
}
Perhaps you should have an array of the mana ball bools. If you use one, set the last true element to false. Then have one method that counts up and sets the first false element back to true.
I might do something like this :
bool[] manaBalls = { true, true, true, true };
bool usingCoroutine = false;
void UseMana() {
for(int i = manaBalls.Length - 1; i >= 0; i--) {
if(manaBalls[i]) {
manaBalls[i] = false;
if(!usingCoroutine) {
StartCoroutine("Timer")
}
break;
}
}
}
void ReplenishMana() {
for(int i = 0; i < manaBalls.Length; i++) {
if(!manaBalls[i]) {
manaBalls[i] = true;
if(i == manaBalls.Length - 1) {
StopCoroutine("Timer");
}
return;
}
}
}
You'll want to spice this up and add the timer in appropriately. This is psuedu ish code.
UseMana would go from the end of the array to the front. The first unused one it finds gets used. ReplenishMana does the oppisite. It goes from front to back finding the first false element and sets it back to true. Then it checks if that's the end of the array, if it is, stop the coroutine.
sometimes try Invoke() method for creating delays.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html

Xamarin MotionEventActions.Move never gets hit in custom views onTouch event?

I have an app where I am drawing lines through points to form polygons, I want to be able to have the four corners of the polygon be moveable, I have this code inside of a custom view I've created for drawing polygons:
public override bool OnTouchEvent(MotionEvent e)
{
MotionEventActions action = e.Action;
float x = 0.0f;
float y = 0.0f;
float radius = 20.0f;
// Get the current pointer index
int tempPointerIndex = e.ActionIndex;
x = e.GetX(tempPointerIndex);
y = e.GetY(tempPointerIndex);
// For each point, check to see if the touch fell within the bounds of the circle
for (int i = 0; i < _points.Length; i++)
{
if((x >= _points[i].X - radius && x <= _points[i].X + 20) ||
(y >= _points[i].Y - radius && y >= _points[i].Y + 20))
{
switch (action)
{
case MotionEventActions.Down:
{
// Get the current x/y when not moving so we can calculate the delta x/y in
// move events
lastX = x;
lastY = y;
// Set the global active pointer index
activePointerId = e.GetPointerId(0);
break;
}
case MotionEventActions.Move:
{
int pointerIndex = e.FindPointerIndex(activePointerId);
x = e.GetX(pointerIndex);
y = e.GetY(pointerIndex);
// Find the delta x/y
float deltaX = x - lastX;
float deltaY = y - lastY;
// Move the selected skew handle by the delta x/y
_points[i].X += deltaX;
_points[i].Y += deltaY;
// Force a redraw
this.Invalidate();
break;
}
case MotionEventActions.Up:
{
// Invalidate the active pointer index
activePointerId = global::Android.Views.MotionEvent.InvalidPointerId;
break;
}
case MotionEventActions.Cancel:
{
// Invalidate the active pointer index
activePointerId = global::Android.Views.MotionEvent.InvalidPointerId;
break;
}
case MotionEventActions.PointerUp:
{
int pointerIndex = e.ActionIndex;
int pointerId = e.GetPointerId(pointerIndex);
if(pointerId == activePointerId)
{
// Active pointer going up, choose new active pointer and adjust accordingly
int newPointerIndex = pointerIndex == 0 ? 1 : 0;
lastX = e.GetX(newPointerIndex);
lastY = e.GetY(newPointerIndex);
activePointerId = e.GetPointerId(newPointerIndex);
}
break;
}
}
}
}
return base.OnTouchEvent(e);
}
The case for MotionEventActions.Move never seems to get hit, in fact, the only event that seems to get hit is the down event when I initially hit a point. Also, the condition that checks the bounds of the point works for sure, I've tested it numerous times, so that isn't the issue either, I'm not sure if maybe I'm checking for the event incorrectly, but as far as I can tell this is how both the Xamarin and Android documentation say to handle this event, so I'm not really sure what the problem is, or how to find it. My question is, what exactly am I doing wrong that is causing the move event to not be picked up?
Once you determine if one of your points is in range of the user's touch, start returning true from OnTouchEvent until you get an Up, that way all future touch events become Move events on your custom View and are not redirected to the View's parent.
Down/Move/Up touch event logic:
public override bool OnTouchEvent(MotionEvent e)
{
x = e.GetX(e.ActionIndex);
y = e.GetY(e.ActionIndex);
Log.Debug(TAG, $"{e.Action} : {x} : {y}" );
if (e.Action == MotionEventActions.Down)
{
if (true) // some check if the x/y touch is on or near a moveable point, isDraggingPoint becomes true
isDraggingPoint = true;
else
isDraggingPoint = false;
}
if (e.Action == MotionEventActions.Move)
{
// move your Point, x/y touch for draggingPoint, update display, etc...
}
if (e.Action == MotionEventActions.Up)
{
// save the final x/y touch for draggingPoint, update display, etc...
isDraggingPoint = false;
}
return isDraggingPoint;
}
Output:
[CustomView] Down : 358.5332 : 234.6167
[CustomView] Move : 358.5332 : 234.6167
[CustomView] Move : 352.5305 : 238.6241
[CustomView] Move : 334.8269 : 237.3517
[CustomView] Move : 360.5305 : 246.6073
[CustomView] Move : 360.5305 : 246.6073
[CustomView] Up : 360.5305 : 246.6073

How to constantly sort and refresh elements (e.g. elevator target floor)

I was wondering if any of you Guys could help me out with my school project. I'm working on elevator simulator in WPF. It's quite simple how it works, you press a button on certain floor and elevator goes there. I managed to achieve animation effect by using async method for animation and waiting between iterations like await Task.Delay(10).
This is how my code looks:
6 buttons on different floors (from 4 to -1). Every button is calling animation(x) method, where x = floor where button is placed. This is button 4 for example:
async private void buttonna4_Click(object sender, RoutedEventArgs e)
{
animation(4);
}
So from clicking this button we go to animation(x) method, which looks like that:
public async Task animation(int go_where_from_button)
{
await semafor.WaitAsync();
{
go_where = convert_floor(go_where_from_button);
try
{
if (go_where < Windajo.Margin.Top) //going up
{
for (int i = Convert.ToInt16(Windajo.Margin.Top); i >= go_where; i--)
{
await gui_elements(i);
}
}
if (go_where > Windajo.Margin.Top) //going down
{
for (int i = Convert.ToInt16(Windajo.Margin.Top); i <= go_where; i++)
{
await gui_elements(i);
}
}
}
catch (Exception)
{
label.Content = "some exception";
}
finally
{
semafor.Release();
}
}
}
where:
SemaphoreSlim semafor = new SemaphoreSlim(1); which I use to prevent elevator from going upwards and downwards at once.
go_where is converted value of how far elevator should go till it stops (because I use margins to determine whether elevator moved to desired floor or not).
await gui_elements(i) is a method where I've put all my elevator things like elevator itself, doors, screen with current floor etc so it looks like:
public async Task gui_elements(int i)
{
Windajo.Margin = new Thickness(Windajo.Margin.Left, i, Windajo.Margin.Right, Windajo.Margin.Bottom);
//OTHER ELEMENTS................
await Task.Delay(10);
}
Now it works like that: lets assume that we are on floor 0 I push buttonna3, buttonna4, buttonna1. Elevator will go in exact that order: floor 3 -> floor 4 -> floor 1.
And here is my question: how to make it sort floors correctly to work like normal elevator? So in this case to go floor 4 -> floor 3 -> floor 1 (or floor 1 -> floor 3 -> floor 4). And while it's already moving for example from floor 1 to floor 3 to react if someone pushes button on floor 2.
I was struggling with this all day long. First I tried to make List() of floors desired and then Distinct not unique floors and Sort them but it was not working as it should because (I used foreach and it couldnt update the list while doing operations, at least this is what I think).
Could anyone give me a hint of not complicated and correct way of solving this problem?
I really appreciate any help you can provide.
I think you shouldn't call animation method directly from buttonDown event.
Instead of this, you can create List of inputs and create a Timer and put all the elevator logic in Timer.Tick handler.
The main idea and the main issue is how to calculate next floor (targetFloor).
I suggest to create a list of inputs List<int> inputs, flag that shows is elevator go down or up bool IsGoingUp and two int variables - currentFloor and targetFloor and recalculate target floor every time when user clicks a button, based on direction and on inputs.
Something like this.
List<int> inputs = new List<int>();
int currentFloor = 1;
int targetFloor = 1;
bool IsGoingUp = true;
public MainWindow()
{
InitializeComponent();
System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0,100);
timer.Tick += Timer_Tick;
timer.Start ();
}
private void buttonna4_Click(object sender, RoutedEventArgs e)
{
inputs.Add(4);
// Recalculating target floor based on input
RecalculateTargetFloor();
}
private void Timer_Tick(object sender, EventArgs e)
{
DrawAnimation(); // Draw small step of elevator to targetFloor
if (currentFloor == targetFloor)
RecalculateTargetFloor();
//waiting for another tick of timer.
}
Method DrawAnimation () draws everything based on currentFloor and targetFloor. It also should recalculate target floor to handle when elevator reachs another target floor.
private void RecalculateTargetFloor()
{
if (targetFloor > currentFloor)
{
//going up
GetNextUpperFloor();
return;
}
else if (targetFloor < currentFloor)
{
//going down
GetNextLowerFloor();
return;
}
// Elevator reached target
inputs.RemoveAll(x => x == targetFloor);
if (IsGoingUp)
{
// if there is no any floors to go up - go down
if (!inputs.Any(x => x > currentFloor))
{
IsGoingUp = false;
}
else
{
// or continue journey
GetNextUpperFloor();
}
}
else
{
if (!inputs.Any(x => x < currentFloor))
{
IsGoingUp = true;
}
else { GetNextLowerFloor(); }
}
}
And methods that calculate next station
void GetNextUpperFloor()
{
var newTargetFloors = inputs.Where(x => x < targetFloor && x > currentFloor);
if (newTargetFloors.Any())
{
targetFloor = newTargetFloors.Min();
}
else if (inputs.Any(x => x > currentFloor))
{
targetFloor = inputs.Where(x => x > currentFloor).Min();
}
}
void GetNextLowerFloor()
{
var newTargetFloors = inputs.Where(x => x > targetFloor && x < currentFloor);
if (newTargetFloors.Any())
{
targetFloor = newTargetFloors.Max();
}
else if (inputs.Any(x => x < currentFloor))
{
targetFloor = inputs.Where(x => x < currentFloor).Max();
}
}
You should be carreful with multitasking because you can break List, put some lockers if you have problems with deleting/inserting item from the list simultaneously.

Making breakout game

My friends I made some parts of this game but I have two problems in this game.
1)Problem about distinguishing ball collision with obstacles
1-1)A first problem is related to complex guidelines that I used them for simulation of ball collision with board or ball collision with blocks. These guidelines are not accurate especially when the ball meets with block corner or bottom.
If it is not better for collision distinguish I use a better code. I wrote this code. Are you think that are there better way?
2)How I can do a work that if the ball collision with any obstacle, the obstacle report the collision.
My aim is about using of events.
Are you thinking that I make obstacles as runtime?
If I make as a runtime, how I can make collision event for them?
With best regards
private Point MouseDownLocation;
int step = 2;
int stepleft = 2;
bool flagBottom;
bool flagTop;
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 10;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
ball.Top += step;
ball.Left += stepleft;
//board simulate collision
bool collisonX = ball.Location.X + ball.Width > board.Location.X && ball.Location.X < board.Location.X + board.Width;
bool collisonY = ball.Top + ball.Height == board.Location.Y || ball.Top + ball.Height - 1 == board.Location.Y;
//board2(button1) simulate collision
bool collisonX2 = ball.Location.X + ball.Width > board2.Location.X && ball.Location.X < board2.Location.X + board2.Width;
bool collisonY2 = ball.Top + ball.Height == board2.Location.Y || ball.Top + ball.Height - 1 == board2.Location.Y;
//Collision the ball with under buttons
bool collsionButtonY = ball.Top - ball.Height == board2.Location.Y || ball.Top - ball.Height == board2.Location.Y - 1;
//collision leftwall
bool leftWall = ball.Left == 0 || ball.Left == -1 || ball.Left == 1;
//collision rightwall
bool topWall = ball.Top == 0 || ball.Top == -1 || ball.Top == 1;
bool bottomWall = collisonX && collisonY;
bool toppWall = collisonX2 && collisonY2;
//collision
bool barrier = collisonX2 && collsionButtonY;
//rightwall
bool rightWall = ball.Left + ball.Width == this.ClientSize.Width || ball.Left + ball.Width == this.ClientSize.Width - 1;
// sidewall = collision rightwall or leftwall
bool sideWall = leftWall || rightWall;
//Check the ball hit the ground
bool check = ball.Top + ball.Height < this.ClientSize.Height;
//if topWall true,This means that the ball is hit to the topwall
if (topWall)
{
flagBottom = false;
flagTop = true;
if (stepleft > 0)
{
step = 2;
}
else if (stepleft < 0)
{
step = 2;
}
}
//if bottomWall true,This means that the ball is hit to the board
else if (bottomWall)
{
flagBottom = true;
flagTop = false;
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if barrier true and flagbottom true,This means that the ball is hit to the board2(button1)
else if (barrier && flagBottom)
{
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if toppWall true and flagTop true,This means that the ball is hit to The top button is hit
else if (toppWall && flagTop)
{
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
else if (sideWall)
{
//if leftwall true,This means that the ball is hit to the left side wall
if (leftWall)
{
if (flagTop)
{
stepleft = 2;
}
else if (flagBottom)
{
stepleft = 2;
}
}
//if rightWall true,This means that the ball is hit to the left side wall
else if (rightWall)
{
if (flagTop)
{
stepleft = -2;
}
else if (flagBottom)
{
stepleft = -2;
}
}
}
//check if ckeck==ture,this mean the ball is hit the ground
else if (!check)
{
timer1.Enabled = false;
}
}
private void board_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void board_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
board.Left = e.X + board.Left - MouseDownLocation.X;
}
}
Define each "Wall" as an Object, this will increase your codes readablility. it will also allow you to define an Event for each wall, Listen to t. that way you know which wall has been hit
N.b. this is pseudo code. It wont compile :P
public class Wall
{
int X,Y,W,H;
//Define an event, add a listener to this, becuase we will fire this when there is a collision
public event EventHandler OnCollision;
public void CollisionCheck(Ball playerBall)
{
//1 Check for a collision with the "Ball" object
if(Ball.Rectangle().Intersects(this.Rectangle))
this.OnCollision(this, EventArgs.Empty); //Fire the event, null check might be requried
}
}
I do not know your game but (suspect 2D brick-like game)
Objects/Obstacles
all objects/obstacles can be simplified to rectangular objects
so make list of them with defined parameters like size and position
if they are movable/dropable then also speed and state...
type of object (affects color,scoring,capabilities...)
create member function like update(dt),draw()
create events you like OnHIt,OnCollision,...
for example (C++ pseudo code):
// game object types ...
enum _game_object_type_enum
{
_game_object_type_none=0,
_game_object_type_wall,
_game_object_type_brick1,
_game_object_type_brick2,
_game_object_type_brick3,
_game_object_type_bomb,
_game_object_type_joker1,
_game_object_type_joker2,
...
};
// game object class
class game_object
{
public;
int type; // type of object
float x,y,vx,vy,hx,hy; // position,speed,half size of rectangle
void update(float dt); // this call periodicaly in some timer updates positions,... and call events, dt is time passed
void draw(); // can add some rendering device context ...
};
// whole game class holds the game world/board/map and player(s) ...
class game_board
{
public;
game_object *go; int gos; // list of all objects in game
void update(float dt) { for (int i=0;i<gos;i++) go[i].update(dt); }
void draw() { for (int i=0;i<gos;i++) go[i].draw(); }
}
events and flow control
first define some events you need
either you use global function/pointers for that or as members
depends on your platform and to what you are used to
for example like this:
void OnCollisionFX(game_object o1,game_object o2)
{
// do something ...
}
void (*OnCollision)(game_object o1,game_object o2)=OnCollisionFX;
for player interactions only (like player controlled object collisions test only)
is better to handle this in game_object::update(dt) but you need to add player context
something like game_object::update(dt,plr)
where plr is pointer to player controlled object or player class
if you have massive interactivity between game objects (like brick/brick collisions)
then is better to handle this in game_board::update(dt)
because otherwise you will need to provide references for everything into update call
and that will quickly lead to heap/stack trashing and very slow performance
also more advanced multiple object collision/interaction approaches are better in main game class
here is an example for first case:
void game_object::update(float dt,game_object &plr)
{
// update position
x+=vx*dt;
y+=vy*dt;
// here you should make your own collision test of coarse
if (fabs(x-plr.x)<=hx+plr.hx)
if (fabs(y-plr.y)<=hy+plr.hy)
{
... do what you need like mirror or stop speed or clamp position ...
if (OnCollision) OnCollision(this,plr);
}
}
in second case you should check each object against each other
void game_board::update(float dt)
{
int i,j;
// update position
for (i=0;i<gos;i++)
{
go[i].x+=go[i].vx*dt;
go[i].y+=go[i].vy*dt;
}
// here you should make your own collision test of coarse
for (i=0;i<gos;i++)
for (j=i+1;j<gos;j++) // the lower indexes are already tested
if (fabs(go[i].x-go[j].x)<=go[i].hx+go[j].hx)
if (fabs(go[i].y-go[j].y)<=go[i].hy+go[j].hy)
{
... do what you need like mirror or stop speed or clamp position ...
if (OnCollision) OnCollision(go[i],go[j]);
}
}
performance
you can improve performance by use of type property
for example if some game objets are static then the do not need to update position
if some are indestructible then there can be also some processing avoided and so on ...
[notes]
dt/fps/speed should be combined
so in each frame your player controlled object or any moving object does not move further
then the half size of smallest object
if this is not true then you need better collision test
use line intersection algorithm
last position and actual position gives you one line
and object edge gives you the other one
if booth objects are moving then that is even more complicated :)

Categories

Resources