C# AI for Paddle - c#

I'm having trouble figuring out how to make the computer's paddle move. I have set up the player's paddle using a mouse. This is what I have to move the paddle using mouse. How do I make the computer's paddle move where the ball is going (with chances that the computer will lose)? Cheers!
Form.Cs
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
controller.MoveLeftPaddle(e.Location.Y);
}
Controller.Cs
public void MoveLeftPaddle(int newPlayerPosition)
{
paddlePlayer.MovePlayerPaddle(newPlayerPosition);
}
Paddle.CS
public void MovePlayerPaddle(int newYPosition)
{
position.Y = newYPosition;
}
Now, I have this code that I tried to make the computer's paddle move.
Paddle.CS
public void MoveComputerPaddle(int newY2Position)
{
position.Y = newY2Position;
}
Controller.Cs
public void MoveRightPaddle(int newComputerPosition)
{
if (ball.Position.Y >= paddleComputer.Position.Y)
{
newComputerPosition += BALLSPEED;
}
else if (ball.Position.Y <= paddleComputer.Position.Y)
{
newComputerPosition -= ball.Velocity.Y;
}
}
public void Run()
{
MoveRightPaddle(paddleComputer.Position.Y);
} //im not really sure about this part. this is the only way that I didnt get squiggly line.
then I have a method in Controller.cs to make the ball move,bounce and draw. I use it as well to draw the paddle which is inside the method Run(). Code above

Ideally your paddles for the Computer and the Player would be the same, and you would have a separate controller for each - The PlayerController would take user input and call MovePaddle based on that, wheras the ComputerController would check the ball position to decide how to call MovePaddle.
You could make the ComputerController store the position for the previous X frames, allowing you to tweak difficulty simply by choosing how old the data is that it uses for its decisions.

As 500 - Internal Server Error has pointed out in the comment section, you are only changing the passed in parameter's value (in this case, newComputerPosition), not paddleComputer.Position.Y.
I don't think you need any parameters at all for MoveRightPaddle like so:
public void MoveRightPaddle()
{
if (ball.Position.Y >= paddleComputer.Position.Y)
{
paddleComputer.Position.Y += BALLSPEED; // I don't know why this uses a different value from the else statement
}
else
{
paddleComputer.Position.Y -= ball.Velocity.Y;
}
}
and
public void Run()
{
MoveRightPaddle();
}
However, I am sensing there is a code smell somewhere if you are calling these variables directly, and thus I would suggest looking into ways of addressing this issue.
How to make the right paddle better at moving
Currently, your right paddle will continue follow the ball regardless of whether the ball is heading towards it or not, or if the paddle will go out of bounds or not.
If you know the x direction of the ball, you can quickly assert whether the right paddle even needs to move or not.
For instance:
if (ball_x_direction > 0) // because for the ball to go right, the direction needs to be positive
{
// move paddle here:
}
For checking if the paddle is going to go off screen (only showing for top of screen (i.e. the second condition of MoveRightPaddle)):
if (paddleComputer.Position.Y - ball.Velocity.Y < 0)
paddleComputer.Position.Y = 0;
} else {
paddleComputer.Position.Y -= ball.Velocity.Y;
}

Related

How to reverse an If Statement when conditions are no longer met

In my Unity project, I have an if statement set-up where if the conditions are true, my character's box collider will shrink to a specific value when crouching (along with movement speed change, turning speed, etc). And when my character is not crouching anymore, the box collider (along with the other parameters I mentioned) will return to its original size in the else statement.
However, I don't want to keep track of every parameter I change/need to reverse across all my scripts. In the future, my character's base parameters may change, which'll cause me to have to go back and change every else statement I ever make involving changing my character to its default parameters. I can create variables to store my base parameters so I wouldn't have to worry about copy-pasting values if I change them in Unity. But it'll eventually snowball into spaghetti-code territory if I do this method for every parameter I create/change in my scripts.
Is there a simpler way to code in C# where if an If statement is no longer true, it'll reverse all changes it made?
Psuedo code:
float height = 10.42f;
float movementSpeed = 95.89f;
if (condition1==true && condition2==true){
height = 3.5f;
movementSpeed = 40.125f;
}
*code to reverse all changes the If Statement made when it stops being true*
Is there a simpler way to code in C# where if an If statement is no longer true, it'll reverse all changes it made?
No. If you want to revert to an earlier state you need to save that state in advance, e.g. in variables as you propose in the question.
It's look like buff system , it can be todo and undo player status , And it's expandability , So you can design a buffsystem to do it like this:
public interface IBuff
{
void Do(Player player);
void UnDo(Player player);
}
public BuffAddHeight : IBuff
{
public Do(Player player)
{
player.Height += 100;
}
public UnDo(Player player)
{
player.Height -= 100;
}
}
public BuffSeed : IBuff
{
public Do(Player player)
{
player.speed += 100;
}
public UnDo(Player player)
{
player.speed -= 100;
}
}
public class Player
{
// by the way , you can design a buff container to manager your buff.
public void AddBuff(IBuff buff) { buff.Do(this); }
public void RemoveBuff(IBuff buff) { buff.UnDo(this); }
}

How can I execute code if something is true, continue executing the code indefinitely, but stop evaluating the if statement?

I'm just starting out please excuse vast ignorance.
I'm writing a c# script in unity as part of the essentials training. I'm doing the 3d audio module and I thought I'd try and get a little bit fancier than the scope of this particular lesson which is supposed to be having an object fly through a window in a pre-built scene and make a 3d sound as it moves.
I wanted to make the movement of the object conditional upon a player moving close to it in 3d space. I figured out how to trigger the movement of an object in a script with an if statement that changes the transform parameters of the object the script is attached to when a 'distanceFromObject' variable is < 2. It works, however the script runs in the update section of the script which runs once every frame. This means that the object's transform parameters are changed every frame as expected but of course stops doing so when the distance between the object that's moving and the player exceeds 2.
I see the mistake I've made because if the object moves away when the player gets close then it will inevitably eventually move far enough away that the distanceFromObject variable will grow bigger than 2 whereupon it stops and just hovers in place. I don't know how to fix it though.
I need the script to check the distance between the object and the player every frame so that it will trigger the instance the player gets close enough, and when they get close enough, I need the object to move away, however once it has been triggered to move, I need the object to continue moving, but the script to stop checking what the distance is anymore.
The script looks like this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FlyOff : MonoBehaviour
{
public Vector3 rotateChange;
public Vector3 positionChange;
public float distanceFromObject;
public GameObject character;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
distanceFromObject = Vector3.Distance(character.transform.position, this.gameObject.transform.position);
print (distanceFromObject);
if (distanceFromObject < 2)
{
transform.Rotate (rotateChange);
transform.position += positionChange;
}
}
}
Use flags instead of writing your logic in the if statement :
public class FlyOff : MonoBehaviour
{
// fields removed for more readability
// use a flag that's set to true/false
private bool isCloseEnough = false;
void Update()
{
distanceFromObject = Vector3.Distance(character.transform.position, this.gameObject.transform.position);
print (distanceFromObject);
// set the flag to true when player is close enough
if (distanceFromObject < 2)
{
isCloseEnough = true;
}
// even if the player gets far, the flag will remain true
if (isCloseEnough)
{
transform.Rotate (rotateChange);
transform.position += positionChange;
}
}
}
You can even apply the opposite logic to stop the object to move away when it has reach a certain distance :
if (distanceFromObject < 2)
{
isCloseEnough = true;
}
else if (distanceFromObject > SomeValue)
{
isCloseEnough = false;
}
If I understand correctly you could just add a bool flag and set it once you are close enough. Then you can start moving and skip further distance checks but keep moving forever.
private bool flyAway;
void Update()
{
if(!flyAway)
{
distanceFromObject = Vector3.Distance(character.transform.position, transform.position);
print (distanceFromObject);
if (distanceFromObject < 2)
{
flyAway = true;
}
}
else
{
transform.Rotate (rotateChange);
transform.position += positionChange;
}
}
In general: Avoid using print every frame! Even if you user doesn't see the log in a built app it is still causing overhead!

Collision with walls does not apply when changing ball location

I've been working on a Breakout-style project recently and wanted to make it so that once a user enters the 'cheat mode', they'll be able to move the ball in their desired direction.
Here's what my code looks like: https://gist.github.com/anonymous/7589f4f141888c3c32c7
I've included the return; in my ball class due to the fact that if I don't, the program will not recognise the changes in the X and Y. So basically, my problem is, I want the program to ignore the existing x and y speeds and use the ones provided by the user if the cheat mode is enabled. (Meaning if the user enters the cheat mode, the program should stop the ball where it last was, in terms of x and y coordinates, and let the user move it)
Example of what I mean:
Player enters cheat mode -> Presses Up.
- Ball keeps moving up until it hits the top of the form and then should bounce back in the opposite direction to which it hit the wall.
How do I implement this into my program? I used the 'if statement' for the boolean cheat mode and the return function to exit the moveBall procedure (which ignores the xSpeed and ySpeed but ultimately stops the ball from moving on it's own completely, so the player has to keep clicking Up to move the ball up, otherwise it stays in place.
EDIT:
Okay, I've fixed the issue where the ball wouldn't move, I just added a few more variables for the X and Y change of the ball.
Here's what my code looks like now:
public void moveBall()
{
if (Form1.cheatModeClicked == true)
{
ballRec.X += cheatX;
ballRec.Y -= cheatY;
}
else
{
ballRec.X += xSpeed;
ballRec.Y -= ySpeed;
}
}
However, the ball collision still doesn't want to work, and I don't know why?
It sounds like you need to add a method to the ball class to allow the ball's speed to be set externally. Then you can call that method when keys are pressed, depending on the cheat mode state. The cheat mode state should be stored outside the ball class anyway. The ball itself should only know about ball things and not what a non-ball concept such as cheat mode is.
Here is some pseudo code, I might have missed a few things in the description but hopefully it helps
class Form
{
bool _inCheatMode = false;
Ball ball;
void EnterCheatMode()
{
_inCheatMode = true;
ball.SetSpeed(0, 0); //stop the ball
}
void ExitCheatMode()
{
_inCheatMode = false;
}
void KeyDown(Keys key)
{
if (_inCheatMode)
{
if (key == Keys.Up)
ball.SetSpeed(0, -1);
}
}
}
class Ball
{
public void SetSpeed(x, y)
{
}
}

'Pong' ball not resetting

I'm writing my own Pong game in C# and I'm having some issues with my ball not resetting correctly. I've spent a good hour or two debugging the code but I can't figure it out.
Basically what's supposed to happen is that when the ball is detected to leave the bounds of the window then the Center() method is going to get called and Center() then resets the ball Point by accessing the backing field directly. Now this works, I've verified that it does what it's supposed to by stepping through the code.
Now the weird that happens is that after Center() gets called the ball position reverts back to what it used to be pre-centering. Now the weird thing is that, this reset happens before the set accessor of the Point property is even called. And I'm 100% sure that I'm not accesing the backing field directly in any other place than Center() so I can't figure it out.. Here's the code
namespace Pong
{
internal enum CollisionType
{
Paddle, Boundary
}
class Ball
{
private readonly IGameView view;
private readonly IGameController controller;
private int velocity = 10;
private double angle;
private event CollisionHandler Collision;
private Point _point;
public Point Point
{
get { return _point; }
set
{ // If UpdatePosition() tries to move the ball beyond the boundaries in one tick move the ball to the boundaries
if(value.Y > view.Boundaries.Height || value.Y < 0)
{
_point = new Point(value.X, view.Boundaries.Height);
Collision(CollisionType.Boundary); // Also raise the collision event
}
//If the ball is going to pass the X boundaries of the map then a player should score and the ball should reset
if (value.X > view.Boundaries.Width || value.X < 0)
{
if (angle > 90) // If the angle of the ball of the ball is above 90 degrees then the left paddle was the shooter
{ // So he should score
var scoringPlayer = Array.Find(controller.Players, player => player.Paddle.Orientation.Equals(Orientation.Left));
controller.PlayerScore(scoringPlayer);
Center(scoringPlayer);
}
else // If not, then it's the right paddle
{
var scoringPlayer = Array.Find(controller.Players, player => player.Paddle.Orientation.Equals(Orientation.Right));
controller.PlayerScore(scoringPlayer);
Center(scoringPlayer);
}
}
// If the ball will collide with a player paddle then raise collision event
if (controller.Players.Any(player => player.Paddle.Position.Equals(value)))
{
Collision(CollisionType.Paddle);
_point = value;
}
_point = value;
}
}
public Ball(IGameView view, IGameController controller)
{
this.view = view;
this.controller = controller;
}
public void Center(Player server)
{
//Center the ball, acccess the backing field directly to avoid all the conditional logic in the property
_point = new Point(view.Boundaries.Width / 2, view.Boundaries.Height / 2);
//The ball will start moving from the center Point towards one of the different sides
/*TODO: Apparently the ball moves sideways down towards one of the player paddles, so we must implement more complex
logic to calculate the starting angle of the ball */
angle = (server.Paddle.Orientation.Equals(Orientation.Left)) ? 0 : 180;
}
public void UpdatePosition()
{
//Called to update ball position based on velocity and angle of ball
//For now let's just implement a very primitive movement algorithm
if (angle < 90)
{
Point = new Point(Point.X + velocity, Point.Y);
}
else
{
Point = new Point(Point.X - velocity, Point.Y);
}
}
}
//TODO: Add collision detection through BallCollision Event and implement BallCollisionHandler(CollisionType as Object args)
You set _point = value immediately after you call Center - you need to ensure that your backing field isn't updated after you set it during Center
public Point Point
{
get { return _point; }
set
{ // If UpdatePosition() tries to move the ball beyond the boundaries in one tick move the ball to the boundaries
if(value.Y > view.Boundaries.Height || value.Y < 0)
{
_point = new Point(value.X, view.Boundaries.Height);
Collision(CollisionType.Boundary); // Also raise the collision event
}
//If the ball is going to pass the X boundaries of the map then a player should score and the ball should reset
if (value.X > view.Boundaries.Width || value.X < 0)
{
if (angle > 90) // If the angle of the ball of the ball is above 90 degrees then the left paddle was the shooter
{ // So he should score
var scoringPlayer = Array.Find(controller.Players, player => player.Paddle.Orientation.Equals(Orientation.Left));
controller.PlayerScore(scoringPlayer);
Center(scoringPlayer);
}
else // If not, then it's the right paddle
{
var scoringPlayer = Array.Find(controller.Players, player => player.Paddle.Orientation.Equals(Orientation.Right));
controller.PlayerScore(scoringPlayer);
Center(scoringPlayer);
}
}
// If the ball will collide with a player paddle then raise collision event
if (controller.Players.Any(player => player.Paddle.Position.Equals(value)))
{
Collision(CollisionType.Paddle);
_point = value;
}
_point = value; // <--- This always gets set - even after you call Center above
}
}
Edit:
As Sayse pointed out whilst this is the issue you are getting, it might be useful to move this logic into an 'update' part of the code - this logic seems like it should be part of the IGameController implementation or a IBallController maybe; either that or put an Update method into your Ball class which is called by the game controller when it wants to update all game objects
Property setters ideally shouldn't be side-effecting

How to Get Gameobject position on screen resolution that not passed the resolution to set

I got an object at the screen. At the beginning it is located at x=0,y=0,z=0 later it moves to a different position. I just want to make sure that this object does not move to locations invisible to the user (it's the player main character itself and I neither want the player to be able to go back from his current location nor going forward the camera following him).
Can you explain to me what I need to do here?
I think you're asking:
If a player-character on the screen is moving around, you want the person sitting at the computer to be able to see it always. To do this you need to set up the camera to follow this object.
Here are some links that may get you started:
http://unity3d.com/support/documentation/Components/class-Camera.html
http://unity3d.com/support/documentation/ScriptReference/Camera.html
This tutorial has an example of how to implement a camera that follows the player.
http://unity3d.com/support/resources/tutorials/3d-platform-game.html
using UnityEngine;
using System.Collections;
public class NewGameScript : MonoBehaviour
{
float t=0f;
float v=20f;
float dist;
// Use this for initialization
void Start ()
{
}
void Update ()
{
if(Input.GetKeyUp("up"))
{
if(t<0.1)
{
t +=Time.deltaTime*0.07f;
}
dist=t*v*0.5f;
gameObject.transform.position +=transform.forward*dist;
}
else if(Input.GetKeyUp("down"))
{
if(t>-0.1)
{
t -=Time.deltaTime*0.07f;
}
dist=t*v*0.5f;
gameObject.transform.position +=transform.forward*dist;
}
else if(Input.GetKey("left"))
{
transform.Rotate(0,-0.9f*(dist+1), 0);
gameObject.transform.position +=transform.forward*0.1f*(dist+1);
}
else if(Input.GetKey("right"))
{
transform.Rotate( 0,0.9f*(dist+1),0);
gameObject.transform.position +=transform.forward*0.1f*(dist+1);
}
}
}

Categories

Resources