I began to create a platformer with Monogame and C# recently and got a strange bug with ground collision. I made block and player, both use bounding collisions like this:
public Rectangle Collision
{
get => new Rectangle((int)_pos.X, (int)_pos.Y, _w, _h);
}
//Only for player entity
public Rectangle GroundCollision
{
get => new Rectangle((int)_pos.X, (int)_pos.Y+_w, _w, 1);
}
It works good, though sometimes space appears space ply and ground like so:
.
Both block and player textures are white, but distance in 1 pix is visible. After some jumps (sometimes with movement) may fix it, though after it began to hover again. Here is player update code:
public void Update()
{
if (_movable)
{
Vector2 oldPos = _pos;
_pos += new Vector2(_vel, -_acc);
if(_pos.Y >= 96)
{
bool c = Collides;
}
if (Grounded)
{
_pos += new Vector2(0, _acc);
_acc = 0;
}
/*if (Collides)
{
_pos = oldPos;
}*/
}
}
//Entity Methods
protected void _Move(float dir, float delta)
{
_vel = (float) _speed * dir * delta;
}
protected void _Gravity(float delta)
{
float fallspeed = (float) Math.Round(Phys.gravity * delta * -5f);
if (_acc - fallspeed >= 0)
_acc = fallspeed;
else if (_acc >= 0)
_acc = 0;
}
protected void _Jump(float delta)
{
_acc += _jumpForce * delta * 10f;
}
So, is there any ways to fix this?
Related
So decided to give game dev a try, picked up unity,Now I decided to create a simple ping pong game.
My game has Bat.cs class, ball.cs, and GameHandler.cs.
The GameHandler.cs initializes the batRight, batLeft, ball using the Bat.cs, Ball.cs class and prefabs, it also keeps track of if someone scores then starts a serve by stopping the rally:
public class GameHandler : MonoBehaviour
{
public Bat bat;
public Ball ball;
public Score score;
public static Vector2 bottomLeft;
public static Vector2 topRight;
public static bool rallyOn = false;
public static bool isServingLeft = true;
public static bool isServingRight = false;
public static bool isTwoPlayers = true;
static Bat batRight;
static Bat batLeft;
public static Ball ball1;
static Score scoreLeft;
static Score scoreRight;
// Start is called before the first frame update
void Start()
{
//Convert screens pixels coordinate into games coordinate
bottomLeft = Camera.main.ScreenToWorldPoint(new Vector2(0, 0));
topRight = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
ball1 = Instantiate(ball) as Ball;
//Debug.Log("GameHandler.Start");
batRight = Instantiate(bat) as Bat;
batRight.Init(true);
batLeft = Instantiate(bat) as Bat;
batLeft.Init(false);
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
//Instatiate scores
scoreLeft = Instantiate(score, new Vector2(-2, -4), Quaternion.identity) as Score;
scoreRight = Instantiate(score, new Vector2(2, -4), Quaternion.identity) as Score;
}
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
if (GameHandler.rallyOn)
{
StopCoroutine(batRight.serveAi());
}
}
}
}
public static void increaseScoreByOne(bool isRight)
{
rallyOn = false;
if (isRight)
{
scoreRight.increaseScore();
isServingRight = true;
}
else
{
scoreLeft.increaseScore();
isServingLeft = true;
}
}
}
The ball.cs listens to the static GameHandler.rallyOn and starts moving the ball accordingly, it also changes direction of the ball if it hits a vertical wall or the bat:
public class Ball : MonoBehaviour
{
[SerializeField]
float speed;
float radius;
public Vector2 direction;
public Vector3 ballPosition;
// Start is called before the first frame update
void Start()
{
direction = Vector2.one.normalized; // direction is (1, 1) normalized
//Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
radius = transform.localScale.x / 2;
}
// Update is called once per frame
void Update()
{
ballPosition = transform.position;
if (GameHandler.rallyOn)
{
startRally();
}
}
void startRally()
{
transform.Translate(direction * speed * Time.deltaTime);
Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
if ((transform.position.y + radius) > GameHandler.topRight.y && direction.y > 0)
{
direction.y = -direction.y;
}
if ((transform.position.y + radius) < GameHandler.bottomLeft.y && direction.y < 0)
{
direction.y = -direction.y;
}
if ((transform.position.x + radius) > GameHandler.topRight.x && direction.x > 0)
{
// Left player scores
GameHandler.increaseScoreByOne(false);
//For no, just freeza the script
// Time.timeScale = 0;
//enabled = false;
}
if ((transform.position.x - radius) < GameHandler.bottomLeft.x && direction.x < 0)
{
// right player scores
GameHandler.increaseScoreByOne(true);
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Bat")
{
if (collision.GetComponent<Bat>().isRight && direction.x > 0)
{
direction.x = -direction.x;
}
if (!collision.GetComponent<Bat>().isRight && direction.x < 0)
{
direction.x = -direction.x;
}
}
}
public float getRadius()
{
return radius;
}
}
The bat.cs initiazes the two paddles, and either listens to user input if its 2 players or listens to player and use AI if it is player vs CPU.:
public class Bat : MonoBehaviour
{
float height;
[SerializeField] // this make this appear on editor without making this field public
float speed;
string input;
public bool isRight;
string PLAYER1_INPUT = "PaddleLeft";
string PLAYER2_INPUT = "PaddleRight";
// Start is called before the first frame update
void Start()
{
height = transform.localScale.y;
}
// Update is called once per frame
void Update()
{
if (GameHandler.isTwoPlayers)
{
if (isRight)
{
movePaddleonUserInput(PLAYER2_INPUT);
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
else
{
if (isRight)
{
movePaddleAi();
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
}
void movePaddleAi()
{
if (isRight && GameHandler.ball1.direction.x > 0 && GameHandler.ball1.ballPosition.x > 0)
{
//transform.Translate(direction * speed * Time.deltaTime);
if ((transform.position.y) > GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y < 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
if ((transform.position.y) < GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y > 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
}
}
void movePaddleonUserInput(string input)
{
// move = (-1 -> 1) * speed * timeDelta(this keep move framerate independent)
float move = Input.GetAxis(input) * speed * Time.deltaTime;
//Debug.Log((transform.position.y + height / 2) + " > "+ GameHandler.topRight.y+ "&&" + move +" > 0");
//Restrict paddle movement to to the screen
// (top edge of paddle > Screen top and we are moving up)
if ((transform.position.y + height / 2) > GameHandler.topRight.y && move > 0)
{
move = 0;
}
// (bottom edge of paddle < Screen top and we are moving down)
if ((transform.position.y - height / 2) < GameHandler.bottomLeft.y && move < 0)
{
move = 0;
}
transform.Translate(move * Vector2.up);
}
public void Init(bool isRightPaddle)
{
isRight = isRightPaddle;
Vector2 pos;
if (isRightPaddle)
{
isRight = isRightPaddle;
pos = new Vector2(GameHandler.topRight.x, 0);
// offset since center is the anchor
pos -= Vector2.right * transform.localScale.x;
input = "PaddleRight";
}
else
{
pos = new Vector2(GameHandler.bottomLeft.x, 0);
// offset since center is the anchor
pos += Vector2.right * transform.localScale.x;
input = "PaddleLeft";
}
transform.name = input;
transform.position = pos;
}
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
}
Now I also have score.cs and mainMenu scene , but no need to include that for this question, What I am struggling with now is the AI not stopping after it scores a point, I want the AI paddle to stop for a few seconds before it serves.
As you can see in the code, I added a yield return new WaitForSecondsRealtime(2f);
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
But this only cause the paddle to wait for the first time it scores , and then if it scores again in quick interval, it doesn't wait at all.
Not sure what I doing wrong here, thanks for your time.
The more plausible explanation to me would be that GameHandler.rallyOn and isServing* aren't all being reset to the correct values to prevent the serve from occurring before the coroutine even begins, or another check is needed somewhere to prevent a serve from occurring if all of the correct booleans aren't set. Try placing appropriate breakpoints and stepping through in a debugger.
You'd probably be better off using WaitForSeconds rather than WaitForSecondsRealtime, by the way, at least if there's a chance you might want to allow the game to be paused in the future.
Realized that the coroutine is called multiple times even before its finished due do it being called from update function in GameHandler.cs. Needed a way to check if the co-routine is already running and not start a new one from update if so, used the Game.isServing variable to do so:
public IEnumerator serveAi()
{
GameHandler.isServingRight = false; // coroutine started , no need to start new one
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
}
And my update in GameHandler is already checking for that variable before starting the coroutine:
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
}
}
}
My problem is, that when Im moving against a wall, that there is a little bouncing effect. Here is a video of it:
https://www.dropbox.com/s/t5drxu4aw60nq59/meem.mp4?dl=0
I dont know how to fix it, I already tried everything. I hope someone know a solution for this. Thank you
Here is the movement script:
public class PlayerMovement : MonoBehaviour
{
public float speed;
public float x;
public float y;
public bool canMove;
void FixedUpdate()
{
if (canMove)
{
if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W))
{
GoUp();
}
else if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S))
{
GoDown();
}
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
GoRight();
}
else if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
GoLeft();
}
if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.RightArrow))
{
GoUp();
GoRight();
}
else if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftArrow))
{
GoUp();
GoLeft();
}
else if (Input.GetKey(KeyCode.DownArrow) && Input.GetKey(KeyCode.RightArrow))
{
GoDown();
GoRight();
}
else if (Input.GetKey(KeyCode.DownArrow) && Input.GetKey(KeyCode.LeftArrow))
{
GoDown();
GoLeft();
}
this.transform.position = new Vector2(this.transform.position.x + x, this.transform.position.y + y);
x = 0;
y = 0;
}
}
public void GoUp()
{
y = Time.deltaTime * speed;
}
public void GoDown()
{
y = Time.deltaTime * (-speed);
}
public void GoRight()
{
x = Time.deltaTime * speed;
}
public void GoLeft()
{
x = Time.deltaTime * (-speed);
}
}
Find two suggestions to handle stop going right example. Note they are going to be not debugued code, as I dont know your project details. Also no the most correct in many aspects for the saem reason. Just to give you the idea.
1.- With distance control
public GameObject wall; //ref to wall set in editor
float playerHalfSize = 0f;
float wallHalfSize = 0f;
float bodiesTotDist = 0f;
Start() {
playerHalfSize = transform.scale.x / 2;
wallHalfSize = wall.scale.x / 2; // supposing size is set with scale. Preferably get the size with a collider or the mesh renderer Bounds class inside the respective collider or MeshRenderer classes
bodiesTotDist = playerHalfSize + wallHalfSize;
}
float getDistanceToWall(wall) {
float distance = Vector3.Distance(transform.position, wall.transform.position) - bodiesTotDist;
}
public void GoRight()
{
if (getDistanceToWall() > 0) //this avoids your player x move further to the right
x = Time.deltaTime * speed;
}
If you might still see the bouncing you can try to adjust manually a threshold distance, for example getDistanceToWall() > 0.5f or adjunting the collider.
2.- With a trigger: If you put a trigger a little bit bigger that your wall, when the wall touches the player you can handle in the code also to avoid further x right set.
bool isRightWallTouching = false;
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject == wall) //for the right wall
isRightWallTouching = true;
}
void OnTriggerExit2D(Collider2D other)
{
isRightWallTouching = false;
}
public void GoRight()
{
if (isRightWallTouching > 0) //this avoids your player x move further to the right
x = Time.deltaTime * speed;
}
As told, not debugged code so might have some failures and the chance that you might have many walls, so this suggestion may lead to a lots of bools dirty solution, but hope it can provide you some inspiration to put your game to work and move on :)
I am attempting to create a minigolf game but am having trouble solving how to calculate the direction to hit the ball. I am thinking that it is easiest to hit the ball in the forward direction that the camera is facing, but I get unexpected results after the first hit as the ball will not calculate the correct direction after hitting the first time. How can I set the direction for hitting the ball and then apply the force I am calculating?
This is my script attached to my ball object at the moment. Sorry for the messiness.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Golfball : MonoBehaviour {
public GameObject ball = null;
public GameObject hole = null;
public GameObject cam = null;
public Text distance;
public Text score;
public Slider powerbar;
private int strokes = 0;
private bool isMoving = false;
private bool increasing = true;
private float distanceToHole;
public float minHitPower = 40.0f;
public float maxHitPower = 270.0f;
private float hitPower = 0;
private float powerIncrement = 5.0f;
private float powerMultiplier = 10;
private float ballRollTime = 0;
private Vector3 ballDir;
// Use this for initialization
void Start() {
distance.GetComponent<Text>().text = "Distance To Hole:" + distanceToHole;
ball.GetComponent<Rigidbody> ();
score.GetComponent<Text>().text = "Strokes:" + strokes;
}
// Update is called once per frame
void Update () {
//Allow the ball to be hit if the ball is not null, not currently moving, and the left mouse button is clicked.
if (ball != null) {
if (Input.GetButton("Fire1") && !isMoving) {
calculatePower ();
}
//Hit ball using power level and set ball to moving.
if (Input.GetButtonUp("Fire1"))
{/**********************************************
//Calculate direction to hit ball
ballDir = cam.transform.forward.normalized;
hitBall(hitPower);
isMoving = true;
}**********************************************/
//Detect when the ball stops
if (isMoving) {
ballRollTime += Time.deltaTime;
if (ballRollTime > 1 && GetComponent<Rigidbody> ().velocity.magnitude <= 0.5) {
GetComponent<Rigidbody> ().velocity = Vector3.zero;
GetComponent<Rigidbody> ().angularVelocity = Vector3.zero;
isMoving = false;
}
} else {
ballRollTime = 0;
}
}
//Calculate distance to hole
distanceToHole = Mathf.Round((Vector3.Distance(ball.transform.position, hole.transform.position) * 100f) / 100f);
distance.GetComponent<Text>().text = "Distance To Hole: " + distanceToHole;
Debug.DrawLine(ball.transform.position, ballDir, Color.red, Mathf.Infinity);
}
void calculatePower(){
//Increase power if it is less than the max power.
if (increasing)
{
if (hitPower < maxHitPower)
{
hitPower += powerIncrement * powerMultiplier;
increasing = true;
}
else if (hitPower >= maxHitPower)
{
increasing = false;
}
}
//Decrease power if power level is not increasing until the power hits the minimum level.
if(!increasing) {
//Debug.Log ("Not Increasing");
if (hitPower > minHitPower) {
//Debug.Log ("HitPower: " + hitPower);
hitPower -= powerIncrement * powerMultiplier;
} else if (hitPower <= minHitPower) {
increasing = true;
}
}
//Update the slider
powerbar.value = hitPower / powerMultiplier;
}
void hitBall (float power){
//Add force to the ball
//ball.GetComponent<Rigidbody>().AddForce(new Vector3(0, 0, power));
//Camera.main.transform.forward
ball.GetComponent<Rigidbody>().AddRelativeForce(ballDir * power);
//Increase stroke count
strokes++;
updateScore(strokes);
//Reset the power and power bar level to minimum default after hitting ball
hitPower = minHitPower;
powerbar.value = hitPower / powerMultiplier;
Debug.Log("HitPower Reset: " + hitPower);
}
void updateScore(int stroke)
{
score.GetComponent<Text>().text = "Strokes:" + stroke;
}
}
You'll have to apply the force like that:
ball.GetComponent<Rigidbody>().AddForce(ballDir * power, ForceMode.Impulse);
But you'll probably have to play with your 'power' variable.
Also note that you want to use impulse because you are hitting the ball and not applying force for some period of time.
The ballDir * power multiples the ballDir vector by your float number. You probably already know how it works, but here is the rundown:
scalarValue * new Vector(x0, x1, ..., xn) == new Vector(scalarValue * x0, scalarValue * x1, ... scalarValue * xn);]
You might also want to get rid of direction's y component so that your ball doesn't fly into the air (you are playing minigolf, right?)
ballDir.y = 0;
I am using XNA to make a tank game. I've implemented a feature to shoot bullets using a list. After shooting, I want to test if the bullet has gotten close to the boundaries of the screen. If so, remove that particular bullet from the list.
The error appears only when I have more than one bullet on the screen at any given time. Here is the code:
Tank Class:
List<Bullet> bulletList = new List<Bullet>();
bool spacebarPrepared = true; //for shooting every 0.5 seconds
short count = 0;
//Shoot
if (Keyboard.GetState().IsKeyDown(Keys.Space) && spacebarPrepared == true)
{
bulletList.Add(new Bullet(sprBullet, position, turretDirection, turretAngle));
spacebarPrepared = false;
}
if (spacebarPrepared == false)
{
spacebarCount += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (spacebarCount > 0.5)
{
spacebarPrepared = true;
spacebarCount = 0;
}
}
//Update bullets
foreach (Bullet bullet in bulletList)
{
bullet.Update(bounds);
}
count = (short)bulletList.Count;
//Remove unwanted bullets
for (short i = 0; i < count; i++)
{
if (bulletList[i].Alive == false)
{
bulletList.Remove(bulletList[i]);
}
}
Bullet Class:
class Bullet
{
Texture2D spr;
Vector2 origin, pos, dir, turretLength;
float rotation, scale, turretLeng;
short speed;
bool alive = true;
public Bullet(Texture2D sprite, Vector2 position, Vector2 direction, float angle)
{
spr = sprite;
scale = 0.15f;
turretLeng = (110 + spr.Width) * scale;
speed = 5;
rotation = angle;
pos = position;
dir = direction;
origin = new Vector2(spr.Width / 2, spr.Height / 2);
FindTurretLength();
}
public void Draw(SpriteBatch spriteBatch)
{
Matrix bulletTranslation = Matrix.CreateRotationZ(rotation) * Matrix.CreateTranslation(pos.X + turretLength.X, pos.Y + turretLength.Y, 0);
spriteBatch.Begin(SpriteSortMode.BackToFront, null, null, null, null, null, bulletTranslation);
spriteBatch.Draw(spr, Vector2.Zero, null, Color.White, 0, origin, 0.15f, SpriteEffects.None, 1f);
spriteBatch.End();
}
public void Update(Vector2 boundary)
{
pos += dir * speed;
if (pos.X < 50 || pos.X > boundary.X - 50 || pos.Y < 50 || pos.Y > boundary.Y - 50)
{
alive = false;
}
}
public void FindTurretLength()
{
turretLength = new Vector2(turretLeng * dir.X, turretLeng * dir.Y);
}
public Vector2 Pos
{
get
{
return pos;
}
set
{
pos = value;
}
}
public bool Alive
{
get
{
return alive;
}
set
{
alive = value;
}
}
}
What I noticed myself when debugging was that my own 'count' variable = 2, yet the bulletList.Count = 1. Could that be the problem? How is that occurring?
Any help is greatly appreciated.
The problem is in your for loop that removes bullets.
Lets say you have a list of 10 bullets (indexes 0 - 9) when you start the loop. The 1st bullet (at index 0) gets removed....now your list has 9 bullets (indexes 0 - 8), but the count variable has not been updated so your for loop still thinks it has 10.
When you reach the point where "i" is greater than the ACTUAL amount of bullets alive, you'll get the "Index was out of range." error.
There are multiple ways you can fix this error.
I would go for:
bulletList.RemoveAll(x => !x.Alive);
I'm creating a 2D game based on asteroids. And In that game I need to thrust the ship in a direction.
I'm able draw the ship, so that it turns around. But when it comes to moving it forward my problem occours.
I don't seem to be able to get my head around this. (This whole making games thing is new to me ^^)
The player.cs
protected Vector2 sVelocity;
protected Vector2 sPosition = Vector2.Zero;
protected float sRotation;
private int speed;
public Player(Vector2 sPosition)
: base(sPosition)
{
speed = 100;
}
public override void Update(GameTime gameTime)
{
attackCooldown += (float)gameTime.ElapsedGameTime.TotalSeconds;
// Reset the velocity to zero after each update to prevent unwanted behavior
sVelocity = Vector2.Zero;
// Handle user input
HandleInput(Keyboard.GetState(), gameTime);
if (sPosition.X <= 0)
{
sPosition.X = 10;
}
if (sPosition.X >= Screen.Instance.Width)
{
sPosition.X = 10;
}
if(sPosition.Y <= 0)
{
sPosition.Y = 10;
}
if (sPosition.Y >= Screen.Instance.Height)
{
sPosition.Y = 10;
}
// Applies our speed to velocity
sVelocity *= speed;
// Seconds passed since iteration of update
float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
// Multiplies our movement framerate independent by multiplying with deltaTime
sPosition += (sVelocity * deltaTime);
base.Update(gameTime);
}
private void HandleInput(KeyboardState KeyState, GameTime gameTime)
{
if (KeyState.IsKeyDown(Keys.W))
{
//Speed up
speed += 10;
sVelocity.X = sRotation; // I know this is wrong
sVelocity.Y = sRotation; // I know this is wrong
}
else
{
//Speed down
speed += speed / 2;
}
if (KeyState.IsKeyDown(Keys.A))
{
//Turn left
sRotation -= 0.2F;
if (sRotation < 0)
{
sRotation = sRotation + 360;
}
}
if (KeyState.IsKeyDown(Keys.D))
{
//Turn right
sRotation += 0.2F;
if (sRotation > 360)
{
sRotation = sRotation - 360;
}
}
}
Am I close, or seriously far from right?
sRotation is an angle, sVelocity is a velocity. You need trigonometry.
for instance, you could use something like that (I didn't test the signs for correctness):
if (KeyState.IsKeyDown(Keys.W))
{
//Speed up
speed += 10;
sVelocity.X = Math.cos(sRotation * 2 * Math.PI / 360);
sVelocity.Y = -Math.sin(sRotation * 2 * Math.PI / 360);
}
Would that solve your problem?
EDIT: your "speed down" formula is wrong. You are currently adding speed/2 with speed, you should have something along:
speed = speed / 2; // note the "=", not "+="
Also, it would probably be preferable to use something like:
if (speed > 0) {
speed -= 5;
} else {
speed = 0;
}