ignoring "collision" in a pacman game - c

i am almost done with my pixel pacman
and im trying to figure out how the monsters should avoid the collision with the power up and the energizer pills
if you run the game you will see dots which represents
yellow is the pacman
red are the ghosts
purple are simple pills
green are energizer pills(if you eat them you can eat the ghosts).
my problem here is that the im having hard time that the monsters will not "eat" the red or green dots. here is my main struct
struct info {
int curX;
int curY;
char color;
int alive;
};
also every monster move is represented like this
if ( rand1 == 1){ //random up
if(infos[i].curY > 50){
for (j = 0 ;j < 18 ; j++){
set_board(infos[i].curX,infos[i].curY,0);
set_board(infos[i].curX,--infos[i].curY,4);
if the monster is the same location as the pixel it will override it( a thing that i dont want to happen)

It seems that your issue is a display one, not a game logic one. From what I understand, when the ghost goes over the pellets, they get erased. It seems that the answer here is simply to redraw the pellets after the ghost goes over them. You call this pixel pacman: does that mean that every entity is a displayed as a one pixel ? If so, the solution is simply to turn the pixel back to its original colour instead of black (I guess that is the colour you chose when there is nothing to display) when the ghost has moved to the next location.

Related

What is the most efficient way to put multiple colours on a window, especially in frame-by-frame format?

I am making a game with C and X11. I've been trying for quite a while to find a way to put different coloured pixels on a window, frame by frame. I've seen fully developed games get thousands of frames per second. What is the most efficient way of doing this?
I have seen 2-coloured bitmaps with XImages, allocating 256 colours on a fade of black-white, and using XPutPixel with XImages (which I wasn't able to figure how to create an XImage properly that could later have pixels put on it).
I have made this for loop that creates a random image, but it is, obviously, pixel-by-pixel instead of frame-by-frame and takes 18 seconds to render one entire frame.
XColor pixel;
for (int x = 0; x < currentWindowWidth; x++) {
for (int y = 0; y < currentWindowHeight; y++) {
pixel.red = rand() % 256 * 256; //Converting 16-bit colour to 8-bit colour
pixel.green = rand() % 256 * 256;
pixel.blue = rand() % 256 * 256;
XAllocColor(display, XDefaultColormap(display, screenNumber), &pixel); //This probably takes the most time,
XSetForeground(display, graphics, pixel.pixel); //as does this.
XDrawPoint(display, window, graphics, x, y);
}
}
After three or so more weeks of testing things off and on, I finally figured out how to do it, and it was rather simple. As I said in the OP, XAllocColor and XSetForground take quite a bit of time (relatively) to work. XDrawPoint also was slow, as it does more than just put a pixel at a point on an image.
First I tested how Xlib's colour format works (for the unsigned long int represented as pixel.pixel, which was what I needed XAllocColor for), and it appears to have 100% red set to 16711680, 100% green set to 65280, and 100% blue set to 255, which is obviously a pattern. I found the maximum to be a 50% of all colours, 4286019447, which is a solid grey.
Next, I made sure my XVisualInfo would be supported by my system with a test using XMatchVisualInfo([expected visual info values]). That ensures the depth I will use and the TrueColor class works.
Finally, I made an XImage copied from the root window's image for manipulation. I used XPutPixel for each pixel on the window and set it to a random value between 0 and 4286019448, creating the random image. I then used XPutImage to paste the image to the window.
Here's the final code:
if (!XMatchVisualInfo(display, screenNumber, 24, TrueColor, &visualInfo)) {
exit(0);
}
frameImage = XGetImage(display, rootWindow, 0, 0, screenWidth, screenHeight, AllPlanes, ZPixmap);
while (1) {
for (unsigned short x = 0; x < currentWindowWidth; x += pixelSize) {
for (unsigned short y = 0; y < currentWindowHeight; y += pixelSize) {
XPutPixel(frameImage, x, y, rand() % 4286019447);
}
}
XPutImage(display, window, graphics, frameImage, 0, 0, 0, 0, currentWindowWidth, currentWindowHeight);
}
This puts a random image on the screen, at a stable 140 frames per second on fullscreen. I don't necessarily know if this is the most efficient way, but it works way better than anything else I've tried. Let me know if there is any way to make it better.
Thousands of frames per second is not possible. The monitor frequency is about 100 Hz, or 100 cycles per second, that's roughly the maximum frame rate. This is still very fast. Human eye wouldn't pick up faster frame rates.
The monitor response time is about 5ms, so any single point on the screen cannot be refreshed more than 200 times per second.
8-bit is 1 byte, so 8-bit image uses one byte per pixel, each pixel is from 0 to 256. The pixel doesn't have red, blue, green component. Instead each pixel points to an index in the color table. The color table holds 256 colors. There is a trick where you keep the pixels the same and change the color table, this makes the image fade in and out or do other weird things.
In a 24-bit image, each pixel has blue, red, green component. Each color is 1 byte, so each pixel is 3 bytes, or 24 bits.
uint8_t red = rand() % 256;
uint8_t grn = rand() % 256;
uint8_t blu = rand() % 256;
A 16-bit image uses an odd format to store red, blue, green. 16 is not divisible by 3, often times 2 colors are assigned 5-bits, and the 3rd color gets 6-bits. Then you have to fit these colors on one uint16_t sized pixel. It's probably not worth it to explore this.
The slowness of your routine is because you are painting one pixel at a time. You should paint to a buffer instead, and render the buffer once per frame. You might consider using other frame works like SDL. Other games may use things like OpenGL which takes advantage of GPU optimization for matrix operation etc.
You must use a GPU. GPUs have a highly parallel architecture optimized for graphics (hence the name). To access the GPU you will use an API like OpenGL or Vulkan or make use of a Game Engine.

C - Creating animation in terminal - auto-updating 2D array

I'm trying to make an animation which will make a basic circle from dots. I got stuck, because i do not know how to make an array to auto-update herself to make an animation. My program has an issue, because it shows only the last point on circle and other, previous points has vanished due to system("clear") command, but i do not know how to make it the proper way.
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void){
char tab[43][132];
int a, b, t;
double x_kropki, y_kropki;
for (t=0 ; t<360 ; t++) {
x_kropki=floor(10*cos((t*pi)/180))+60;
y_kropki=floor(10*sin((t*pi)/180))+20;
for (a=0 ; a<43 ; a++, printf("\n")) for (b=0 ; b<132 ; b++) {
if ((int)y_kropki==a && (int)x_kropki==b){
tab[a][b]='.';
printf("%c", tab[a][b]);
}else {
tab[a][b]=' ';
printf("%c", tab[a][b]);
}
}
system("clear");
}
return 0;
}
What is the animation supposed to look like? Do you want the circle to grow slowly? Then you need to add a delay (sleep or similar) or else it will finish the whole process too quickly for the screen to draw and for your eyes to notice.
Also you should not clear the progress after every new dot (of the 360 dots in total, it seems). To achieve that, you will need to change your approach a bit. Here's what the loop could look like:
Draw nothing
Draw dot 1
Clear
Draw dot 1 and 2
Clear
Draw dot 1 and 2 and 3
You see that after clearing, you need to repeat printing the progress so far. At loop iteration 180, you need to print the last 179 dots again plus the 180th. Wait a few milliseconds, then clear, then the same for 181.
How you do that? You repeat the for loop:
int dot, maxDots;
for (maxDots = 0; maxDots < 360; maxDots++) {
for (dot = 0; dot < maxDots; dot++) {
// your location calculations and printing for each dot
}
system("clear");
}
This should at least give you some kind of growing circle. But you will notice that the printing approach is hard to get right, because once a line has been finished, you cannot go back. If you start at the top and go your way around 180 degrees, down line by line, you will then need to go up line by line until you reach the top again. That won't work easily. Instead of printing directly, as #Weather Vane suggested, store the to-be-printed result of each animation stage in a buffer. That is an abstraction of on-screen coordinates. A very simple approach would be a two-dimensional array that you can manipulate freely, then print the whole array en bloc.

Arduino increment operators does not affect variable?

I am writing a program that interacts with the LED's connected on my breadboard that will simulate a "ball" bouncing up and down. Everything has worked correctly up until the point where the height of the bounce decrements (simulating loss of momentum). The LED's keep lighting on past the 9th LED and start acting bizarre.
The problems arose in this line of code:
digitalWrite(ledPin[activeLED], HIGH);
activeLED += dir;
if (activeLED == bounceLimit){
dir = -1;
bounceLimit--;
}
if (activeLED == 0) {
dir = 1;
}
The activeLED is the LED being lit, they light in succession to the top until it hits the bounceLimit variable, where it changes direction and lights downward until zero and starts upwards again. The problem lies that in the next time it goes up, the bounceLimit should be set lower at 8 (then 7, 6, etc.) but it seems that it isn't set any lower and the LED's continue to light to the top and then start to act weird.
I managed to fix it by adding another condition
if (activeLED == bounceLimit && dir = 1){
dir = -1;
bounceLimit--;
}
But why is the extra condition needed? Wouldn't the limit be hit only when the direction is upwards (1) anyways?
So if bounceLimit is (say) 9 to start, when you hit the top you take one away to make bounceLimit equal to 8. But then when the LED goes down in the very next iteration the active LED is then also 8, which triggers your if statement again.

Motor conrolling through C

I am working on a NXT lego mindstorm robot and I am building the line follower robot with single reflected light sensor and I am programming in C Language.
the sensor converts the raw Analogue value to digital value with the range from 0 - 1023.
I have to code that of the line is black then motor will move forward and if the there is no line (white base) then stop and if there is grey (in between white and black line) then slightly move right and then left differently to find the lost black line .
So the code is like
While (1)
{
a=ecrobot_get_light_sensor(port_led); //storing the A/D converted value in variable
while (a<300) // White area
{
ecrobot_status_monitor("White Area");
nxt_motor_set_speed(port_motor_l, 0, 1); // left motor turns off
nxt_motor_set_speed(port_motor_r, 0, 1); // right motor turns off
}
while (a>=600) // Black Line
{
ecrobot_status_monitor("Black Area");
nxt_motor_set_speed(port_motor_l, 100, 1); // left motor turns on
nxt_motor_set_speed(port_motor_r, 100, 1); // right motor turns on
}
while (a>=300 || a<600) // Robot loosing the black line
{
ecrobot_status_monitor("grey Area");
nxt_motor_set_speed(port_motor_l, 50, 1); // left motor move forward
nxt_motor_set_speed(port_motor_r, -50, 1); // right motor move backward
delay_ms(200)
nxt_motor_set_speed(port_motor_l, -50, 1); // left motor move backward
nxt_motor_set_speed(port_motor_r, 50, 1); // right motor move forward
delay_ms(200)
}
Problem is that if the robot loses the line then start moving clockwise without stopping and moving towards the anticlockwise after 200 ms delay .
What is the problem with my code ?
How can i stop the motor after this interval and motor should move in other direction after this interval in search of line and then it will surely find a line
Thanks!
One solution is to change all the while statements inside your while(1) loop into if statements.
For example, in your last while statement, when the robot looses the black line, your robot will spin clock-wise and then spin counterclockwise for 200ms in each direction regardless of the new values read from your sensor. This is because the last while statement will finish its execution first before your a gets updated.
I see a couple of things,
Some semicolons missing. Im sure thats not the case in your real code, since it wouldn't even compile. Also try and have proper parenthesis in your statements (better practise :-)
You also need to re-read the sensor while in the loops to avoid dead lock!!!
Also as mentioned, use if/else if statements in a big while loop.
You can add some thresholds to make it smoother :-)
Good luck

How to make my robot move in a rectangular path along the black tape?

I am working on a robot, it's part of the summer robotics workshop in our college. We are using C-STAMP micro controllers by A-WIT. I was able to make it move, turn left, turn right, move backward. I have even managed to make it go along the black tape using a contrast sensor.
I send the robot at 30-45 degrees toward the black tape on the table and it aligns itself and starts to move along the black tape. It jerks a little, probably due to my programming logic below, it's running a while-loop and constantly checking if-statements, so it ends up trying to turn left and right every few milliseconds, which explains the jerking part. But it's okay, it works, not as smooth as I want it to work but it works! Problem is that I can't make my robot go into a rectangular path of the black tape. As soon as it reaches the corner of the black tape it just keeps going straight instead of making left or right turn.
My 2 sensors are located right underneath the robot, next to the front wheel, almost at the floor level. It has "index" value ranging from 0 to 8. Eight being the brightest contrast and zero being the darkest contrast. So when the robot moves into the black-tape-zone, the index value drops, and based on that, I have an if-statement telling my robot to either turn left or right.
Here's my attempt. To avoid confusion I didn't post the entire source code, but only the logical part responsible for the movement of my robot along the black tape.
while(1) {
// don't worry about these.
// 10 and 9 represent Sensor's PIN location on the motherboard
V = ANALOGIN(10, 1, 0, 0, 0);
V2 = ANALOGIN(9, 1, 0, 0, 0);
// i got this "formula" from the example in my Manual.
// V stands for voltage of the sensor.
// it gives me the index value of the sensor. 0 = darkest, 8 = lightest.
index = ((-(V - 5) / 5) * 8 + 0.5);
index2 = ((-(V2 - 5) / 5) * 8 + 0.5);
// i've tweaked the position of the sensors so index > 7 is just right number.
// the robot will move anywhere on the table just fine with index > 7.
// as soon as it drops to or below 7 (i.e. finds black tape), the robot will
// either turn left or right and then go forward.
// lp & rp represent left-wheel pin and right-wheel pin, 1 means run forever.
// if i change it from 1 to 100, it will go forward for 100ms.
if (index > 7 && index2 > 7)
goForward(lp, rp, 1);
if (index <= 7) {
turnLeft(lp, rp, 1);
goForward(lp, rp, 1);
// this is the tricky part. i've added this code last minute
// trying to make my robot turn, but i didn't work.
if (index > 4) {
turnLeft(lp, rp, 1);
goForward(lp, rp, 1);
}
}
else if (index2 <= 7) {
turnRight(lp, rp, 1);
goForward(lp, rp, 1);
// this is also the last minute addition. it's same code as above
// but it's for the 2nd sensor.
if (index2 > 4) {
turnRight(lp, rp, 1);
goForward(lp, rp, 1);
}
}
}
I've spent the entire day trying to figure it out. I've pretty much exhausted all avenues. Asking for the solution on stackoverflow is my very last option now.
Thanks in advance!
If you have any questions about the code, let me know, but comments should be self-explanatory.
This is my goForward function in case anyone wonders:
void goForward(BYTE lp, BYTE rp, WORD t)
{
WORD i;
for(i = 0; i < t; i = i + 1){
PULSOUT(lp, 400, 1, 1);
PULSOUT(rp, 800, 1, 1);
PAUSE(17);
}
}
UPDATE: Here's what I've come up with so far. I've erased all my if-statements that I've posted earlier and decided to write the logic from scratch:
// if there's enough bright light in both sensors at the same time
// robot will move forward forever.
if (index > 7 && index2 > 7)
goForward(lp, rp, 1);
// but if there's not enough bright light anymore (i.e. reached black tape)
// proceed to the else-statement.
else {
// if left sensor detects the black tape then turn right
// if doesn't detect the black tape then keep going forward
if (index2 <= 7)
turnRight(lp, rp, 1);
else
goForward(lp, rp, 1);
// if right sensor detects the black tape then turn left
// if it doesn't detect the black tape then keep going forward
if (index <= 7)
turnLeft(lp, rp, 1);
else
goForward(lp, rp, 1);
}
// The reason for turnLeft and turnRight is to keep robot re-alligning
// to the black tape. It will happen so fast (every 1ms) that the jerking
// shouldn't even be noticeable.
You need to trap the sudden occurrence: [cycle n] "I see the tape" -> [cycle n+1] "I don't see the tape" that happens when you encounter a corner.
A state machine is a good way of handling this type of problem. With a state machine the code for a specific state is isolated, it only runs when the state is true. This isolation prevents "cross-talk" and gives you one known code block for each state.
Given your example the flow might be something like:
:Loop
State == Moving forward and on tape.
read sensors
delta = abs(valueLastCycle - valueThisCycle);
if (delta >= bigChangeValue){
// the tape was just gone.
// change state and handle this situation.
CurrentState = suddenValueChange;
}else
if (index <= 7) {
turnLeft(lp, rp, 1);
goForward(lp, rp, 1);
else if (index2 <= 7) {
turnRight(lp, rp, 1);
goForward(lp, rp, 1);
}
...
State == suddenValueChange
...
code that handles sudden value change event
maybe:
Stop Robot;
Move backwards slowly until on tape or distance x
etc...
Goto Loop
Increasing the scan rate might seem to help....but the faster the robot moves the faster your scan rate....i.e. You might still jump from on tape -> off tape in which case your current code flounders.
My guess is that the goForward immediately after the turnLeft/TurnRight "cancels" the turning?
It depends on how turning is implemented though
Make sure your "plan" makes sense before worrying about the code.
Start by moving the robot around by hand and observing when the sensors pass over black and white areas. Try to come up with a behaviour, and simulate it by hand. If this doesn't work as you want, then you need to revise the behaviour.
A suggestion: You may wish to add some more loops to ensure that if something seems wrong, the robot corrects itself before resuming normal behaviour. (E.g. rather than turning right/left for 100ms, do that behaviour as long as it takes for the sensors to see the right thing.)
Does your while loop run fast enough to catch a corner? If both sensors report that they are on the tape, and in the next cycle both sensors are off the tape, you can't detect that, right? The sensor reports the same values (8) for being on the tape and off the tape?
Try making your code faster. Without seeing the entire code, it's hard to make a recommendation, but it seems that you might be evaluating if statements that are not necessary. Add an ELSE after the first IF, once you know that you are going straight.
It seems that your goforward implementation is blocking the loop for too long. 1 does not mean run forever, it does one pass of the for-loop, and then you PAUSE 17 (msec?). What's the PAUSE for? Remove it. This probably causes the jerking, and it prevents the next set of sensor values from coming in.
Right now, by the looks of your code, every time the robot sees black, it goes forward forever. I'm not really sure how going forward is implemented.
In pseudocode, your code says:
if you see black
go forward forever
if you don't see black
turn left or right
Do you see how your robot would go forward forever with that kind of logic? Again, I have no idea how going forward is implemented so I could be wrong.

Resources