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 :)
Related
I tried two different way to collect coins and both didn't work. I don't know what I'm doing wrong. I'm coding in c#. Is there something I'm missing or is there something I'm supposed to do beforehand?
Here is method number 1:
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox && x.Tag == "coin")
{
if (((PictureBox)x).Bounds.IntersectsWith(pacman.Bounds))
{
this.Controls.Remove(x); //remove that point
score++; // add to the score
}
}
}
and Here is method number 2:
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox)
{
if ((string)x.Tag == "coin" && x.Visible == true)
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
score += 1;
x.Visible = false;
}
}
}
}
This is work in progress so the code is still missing some parts. Here is a bit of the source code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Pac_Man_Game_Clone
{
public partial class Form1 : Form
{
bool goup, godown, goright, goleft, isGameOver;
int score, playerSpeed, redGhostSpeed, yellowGhostSpeed, pinkGhostX, pinkGhostY;
public Form1()
{
InitializeComponent();
restGame();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void keyisdown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Up)
{
goup= true;
}
if(e.KeyCode == Keys.Down)
{
godown= true;
}
if(e.KeyCode == Keys.Left)
{
goleft= true;
}
if(e.KeyCode == Keys.Right)
{
goright= true;
}
}
private void keyisup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
goup = false;
}
if (e.KeyCode == Keys.Down)
{
godown = false;
}
if (e.KeyCode == Keys.Left)
{
goleft = false;
}
if (e.KeyCode == Keys.Right)
{
goright = false;
}
}
private void mainGameTimer(object sender, EventArgs e)
{
txtScore.Text = "Score: " + score;
//moving pacman
if(goleft == true)
{
pacman.Left -= playerSpeed;
pacman.Image = Properties.Resources.left;
}
if(goright == true)
{
pacman.Left += playerSpeed;
pacman.Image = Properties.Resources.right;
}
if(godown == true)
{
pacman.Top += playerSpeed;
pacman.Image = Properties.Resources.down;
}
if(goup == true)
{
pacman.Top -= playerSpeed;
pacman.Image = Properties.Resources.Up;
}
//leaving the parameters
//left and right
if (pacman.Left < -10)
{
pacman.Left = 680;
}
if (pacman.Left > 680)
{
pacman.Left = -10;
}
//up and down
if (pacman.Top < -10)
{
pacman.Top = 550;
}
if (pacman.Top > 550)
{
pacman.Top = -10;
}
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox)
{
if ((string)x.Tag == "coin" && x.Visible == true)
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
score += 1;
x.Visible = false;
}
}
}
//runs through wall
if ((string)x.Tag == "wall")
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
// run game over
}
}
//bumps to ghost
if ((string)x.Tag == "ghost")
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
// run game over
}
}
}
//moving ghosts
redGhost.Left += redGhostSpeed;
if (redGhost.Bounds.IntersectsWith(pictureBox1.Bounds || redGhost.Bounds.IntersectsWith(pictureBox2.Bounds))
{
redGhost += redGhostSpeed;
}
if (score == int.MaxValue)
{
//run game over
}
}
private void restGame()
{
txtScore.Text = "Score: 0";
score= 0;
redGhostSpeed = 5;
yellowGhostSpeed = 5;
pinkGhostX = 5;
pinkGhostY = 5;
playerSpeed = 8;
isGameOver= false;
pacman.Left = 7;
pacman.Top= 35;
redGhost.Left = 219;
redGhost.Top = 56;
yellowGhost.Left = 450;
yellowGhost.Top = 447;
pinkGhost.Left = 521;
pinkGhost.Top = 227;
foreach(Control x in this.Controls)
{
if(x is PictureBox)
{
x.Visible= true;
}
}
gameTimer.Start();
}
private void gameOver(string message)
{
}
}
}
Without having the full source code and the visual tree, I can only try to understand why this isn't working. To me looks like the pacman object isn't defined in the same parent as the coins.
The bounds property is relative to the parent control as coordinate origin.
It works well if each element in the collection of controls are in at the same level of the visual tree, with the same parent. If not, intersect will hardly be true because it is checking against two different coordinate origins, and even if returns true, the position on screen could not match.
As your pacman seems to be referred somewhere else than your collection, maybe your control does not have the same parent and will unlikely have the same origin for your pacman and the coin, and the IF...ELSE will never hit. Please be sure to use the same parent for the pacman and the coins.
Another solution is to draw the game objects on a canvas using the drawing primitives, and create ad hoc objects to store the drawing rectangles. This is the preferred solution as using GDI+ objects to draw game elements doesn't perform well. If you use the canvas instead, all you must do is to update the canvas on each drawing loop with the images of your game objects. This way, you will have no issues with the visual tree of the controls.
Edit: as stated in other comments, if you succeed to hit the intersection condition, in the first version of your code you will also face exception for removing items from the collection while iterating it using foreach. In this case, the solution is to iterate the list first and add the items to a new "removedItemsList" and then iterate this new list to remove the items from the controls collection without iterate it.
It's not so efficient, your second solution with visibility in my opinion is far better. It's not efficient for at least two motives: one because every time you remove a control the visual tree updated for each remaining control. Second, you must allocate a new list, and reiterate it every time you hit a coin. Visibility instead only invalidate the control render rectangle, and on the next draw routing it will be draw invisible.
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);
}
}
Made progress on my game and now I need to make the second boss bounce up and down. I figured out how to make the boss go down, but once it touches the lower wall, it stops and won't bounce (move up).
void BossMove()
{
if((BOSS.Top + 10) <(this.Height - BOSS.Height))
{
BOSS.Top += 10;
}
if((BOSS.Height) > 0)
{
BOSS.Top -= 10;
}
}
Here's a simple example using a state variable to represent the direction:
private Boolean goingUp = true;
void BossMove()
{
if (goingUp)
{
if ((BOSS.Top + 10) < (this.Height - BOSS.Height))
{
BOSS.Top += 10;
}
else
{
// possibly force it to snap to specific position
// before going back down?
goingUp = false;
}
}
else
{
if (BOSS.Top > 450)
{
BOSS.Top -= 10;
}
else
{
// possibly force it to snap to specific position
// before going back up?
goingUp = true;
}
}
}
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
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.