python 3.x – Snake game implemented in PyGame and Python3

I know there’s already a whole bunch of similar attempts at this and I’ve looked at a few of them to get some tips. My main aim with this was not to write anything fancy. I wanted to create a simple game with the most basic functionality but write it really well. In other words I’m more interested in making my code professional, efficient and of high quality. One way I’ve tried to do this is to keep the main function simple and use it mostly for initialisation and the game loop, whilst implementing most of the functionality in separate classes and functions. Also, I would appreciate any advice on comments and docstrings because I’m sure mine are far from perfect. I also noticed the clock speed is around 4.5 GHz while playing this, so I think this could definitely do with an efficiency boost.

#!/usr/bin/env python3

import pygame as pg
from random import randint

# Define window parameters
BLOCK_SIZE = 20
WIN_SIZE = 500


class Head():
    blue = (0, 0, 255)  # Colour of snake
    start_params = (BLOCK_SIZE * 0.05, BLOCK_SIZE * 0.05,
                    BLOCK_SIZE * 0.9, BLOCK_SIZE * 0.9)

    def __init__(self, pos):
        """Head of snake"""
        self.x = pos(0)
        self.y = pos(1)
        self.last_x = self.x
        self.last_y = self.y
        self.direction = (0, -BLOCK_SIZE)
        self.square = None

    def make_block(self):
        """
        Create a surface to contain a square
        Draw a square Rect object onto said surface
        """
        self.square = pg.Surface((BLOCK_SIZE, BLOCK_SIZE), pg.SRCALPHA)
        # Draw a square onto the "square" surface
        pg.draw.rect(self.square, self.blue, self.start_params)

    def update_pos(self):
        """Last coords are used to update next block in the snake"""
        self.last_x = self.x
        self.last_y = self.y
        self.x += self.direction(0)
        self.y += self.direction(1)

    def change_direction(self, new_dir):
        """Change direction of snake without allowing it to go backwards"""
        if new_dir == 'u' and self.direction != (0, BLOCK_SIZE):
            self.direction = (0, -BLOCK_SIZE)
        elif new_dir == 'd' and self.direction != (0, -BLOCK_SIZE):
            self.direction = (0, BLOCK_SIZE)
        elif new_dir == 'l' and self.direction != (BLOCK_SIZE, 0):
            self.direction = (-BLOCK_SIZE, 0)
        elif new_dir == 'r' and self.direction != (-BLOCK_SIZE, 0):
            self.direction = (BLOCK_SIZE, 0)

    def check_collision(self, pos_list):
        """Check if snake collides with wall or itself"""
        if self.x in (0, WIN_SIZE) or self.y in (0, WIN_SIZE):
            return True

        if (self.x, self.y) in pos_list(3:):
            return True

        return False

    def get_pos(self):
        return (self.last_x, self.last_y)


class Block(Head):
    def __init__(self, next_block):
        """Body of snake"""
        self.next = next_block
        pos = next_block.get_pos()
        self.x = pos(0)
        self.y = pos(1)
        self.last_x = self.x
        self.last_y = self.y
        self.ready = 0

    def update_pos(self):
        """Use position of next block in snake to update current position"""
        self.last_x = self.x
        self.last_y = self.y
        next_pos = self.next.get_pos()
        self.x = next_pos(0)
        self.y = next_pos(1)


def add_block(snake_arr):
    """Extend snake by adding a snake block to the snake array"""
    snake_arr.append(Block(snake_arr(-1)))
    snake_arr(-1).make_block()

    return snake_arr


def check_keypress(input_event, block_object):
    """
    Take input event and change direction if arrow key
    or quit game if esc key or other exit signal
    """
    if input_event.type == pg.QUIT:
        return True
    elif input_event.type == pg.KEYDOWN:
        if input_event.key == pg.K_ESCAPE:
            return True
        elif input_event.key == pg.K_UP:
            block_object.change_direction('u')
        elif input_event.key == pg.K_DOWN:
            block_object.change_direction('d')
        elif input_event.key == pg.K_LEFT:
            block_object.change_direction('l')
        elif input_event.key == pg.K_RIGHT:
            block_object.change_direction('r')

    return False


class Food():
    def __init__(self):
        """Food block, created in the same way as a snake block"""
        self.exists = False
        self.x = None
        self.y = None
        self.square = None

    def add_food(self):
        """If no food present, create a new food block with random position"""
        if self.exists is False:
            # Create a surface to contain a square
            self.square = pg.Surface((BLOCK_SIZE, BLOCK_SIZE), pg.SRCALPHA)
            # Draw a square onto the "square" surface
            pg.draw.rect(self.square, (255, 0, 0),
                         (BLOCK_SIZE * 0.05, BLOCK_SIZE * 0.05,
                          BLOCK_SIZE * 0.9, BLOCK_SIZE * 0.9))

            self.x = randint(1, (WIN_SIZE - BLOCK_SIZE)/BLOCK_SIZE) * BLOCK_SIZE
            self.y = randint(1, (WIN_SIZE - BLOCK_SIZE)/BLOCK_SIZE) * BLOCK_SIZE
            self.exists = True

    def check_if_eaten(self, snake):
        """If snake head is in food block, food is eaten"""
        snake_x, snake_y = snake(0)
        if (self.x <= snake_x <= self.x + BLOCK_SIZE * 0.9) and (self.y <= snake_y <= self.y + BLOCK_SIZE * 0.9):
            self.exists = False
            return True

        return False


def main():
    # Initialise PyGame
    pg.init()

    clock = pg.time.Clock()

    size = (WIN_SIZE, WIN_SIZE)  # Size of window, (width, height)
    black = (0, 0, 0)  # Background colour of window

    # Place head of snake in centre of window
    start_coord = (WIN_SIZE / 2) - (BLOCK_SIZE / 2)

    # Create window
    screen = pg.display.set_mode(size)

    head = Head((start_coord, start_coord))
    head.make_block()

    # Make first three blocks of snake
    snake = ()
    snake.append(head)
    snake = add_block(snake)
    snake = add_block(snake)

    ticker = 0
    game_over = False
    food = Food()
    # Game loop
    while game_over is False:
        # Run game at 60 FPS
        clock.tick(60)
        # Monitor events and check for keypresses
        for event in pg.event.get():
            game_over = check_keypress(event, head)
        if game_over is True:
            continue

        snake_pos = (block.get_pos() for block in snake)
        game_over = head.check_collision(snake_pos)

        # Update snake position every 4 frames
        if ticker == 3:
            for s in snake:
                s.update_pos()
            ticker = 0
        ticker += 1

        food.add_food()
        eaten = food.check_if_eaten(snake_pos)
        if eaten is True:
            snake = add_block(snake)

        # Clear the window before the next frame
        screen.fill(black)
        # Draw block to window
        screen.blit(food.square, (food.x, food.y))
        for s in snake:
            screen.blit(s.square, (s.x, s.y))
        # Swap buffers
        pg.display.flip()

    pg.quit()


if __name__ == "__main__":
    main()
```

beginner – Object oriented Snake Javascript

I have implemented a little snake game with Javascript and Html but unfortunately it doesent really work.
It would be really nice if someone could look over it and give me some feedback about my mistakes.

The Snake Game:

class Snake
{
    constructor (x, y, pressedKey, cellSize, context)
    {
        this.x = x;
        this.y = y;
        this.pressedKey = pressedKey;
        this.cellSize = cellSize;
        this.context = context;
        this.body = ();

        document.addEventListener('keyup', this.handleKeyUp.bind(this))
    }

    handleKeyUp(event) 
    {
        if (event.code === 'ArrowRight' || event.code === 'ArrowLeft' || event.code === 'ArrowUp' || event.code === 'ArrowDown') 
        {
            this.pressedKey = event.code;
        }
    }

    updateBody()
    {
        if (this.body.length > 0)
        {
            this.body.pop();
            this.addBody();
        }
    }

    addBody()
    {
        this.body.unshift(new Body(this.x, this.y, this.cellSize));
    }

    changeDirection(newpressedKey)
    {
        this.pressedKey = newpressedKey;
    }

    move()
    {
        if (this.pressedKey === 'ArrowRight') 
        {
            this.x += 1;
        } 
        else if (this.pressedKey === 'ArrowDown') 
        {
            this.y += 1;
        } 
        else if (this.pressedKey === 'ArrowLeft') 
        {
            this.x -= 1;
        } 
        else if (this.pressedKey === 'ArrowUp') 
        {
            this.y -= 1;
        }
    }

    draw()
    {
        this.context.fillStyle = 'yellow';
        this.context.fillRect(this.x * this.cellSize, this.y * this.cellSize, this.cellSize, this.cellSize);

        //b wie body
        this.body.forEach(b => {
            this.context.fillStyle = 'black';
            this.context.fillRect(b.x * b.cellSize, b.y * b.cellSize, b.cellSize, b.cellSize);
        });
    }

    eatApple(apple)
    {
        return apple.x === this.x && apple.y === this.y;
    }

    eatSnake()
    {
        let gameOver = false;
        this.body.forEach(b => {
            if (b.x === this.x && b.y === this.y)
            gameOver = true;
        });
        return gameOver;
    }

    eatWall()
    {
        let gameOver = false;
        this.body.forEach(b => 
        {
            if (b.x < 0)
            {
                gameOver = true;
            }
            if (b.y < 0)
            {
                gameOver = true;
            }
            if (b.x > 8)
            {
                gameOver = true;
            }
            if (b.y > 8)
            {
                gameOver = true;
            }
        });
        return gameOver;
    }

    update()
    {
        let gameOver = false;
        gameOver = this.eatSnake() || this.eatWall();
        if (!gameOver)
        {
            if (this.eatApple(apple))
            {
                this.addBody();
                apple.newPosition();
            }
            this.updateBody();
            this.move();
        }
    }
}

class Body
{
    constructor(x, y, cellSize)
    {
        this.x = x;
        this.y = y;
        this.cellSize = cellSize;
    }
}

class Apple
{
    constructor(cellSize, context)
    {
        this.x = Math.floor(Math.random() * 8);
        this.y = Math.floor(Math.random() * 8);
        this.cellSize = cellSize;
        this.context = context; 
    }

    newPosition()
    {
        this.x = Math.floor(Math.random() * 8);
        this.y = Math.floor(Math.random() * 8);
    }

    draw()
    {
        this.context.fillStyle = 'red';
        this.context.fillRect(this.x * this.cellSize, this.y * this.cellSize, this.cellSize, this.cellSize);   
    }
}

class Game
{
    constructor(canvas, extent) 
    {
        this.canvas = canvas;
        this.context = this.canvas.getContext('2d');
        this.extent = extent;
        this.cellSize = this.canvas.width / this.extent;

        this.snake = new Snake(0, 0, 'ArrowDown', this.cellSize, this.context, this.extent);
        this.apple = new Apple(this.cellSize, this.context, this.extent)

        setInterval(this.loop.bind(this), 250);   
    }

    drawLine(x1, y1, x2, y2) 
    {
        this.context.beginPath();
        this.context.moveTo(x1, y1);
        this.context.lineTo(x2, y2);
        this.context.stroke();
    }

    drawGrid() 
    {
        for(let i = 1; i < this.extent; i++) 
        {
            this.drawLine(0, i * this.cellSize, this.canvas.width, i * this.cellSize);
            this.drawLine(i * this.cellSize, 0, i * this.cellSize, this.canvas.height);
        }
    }

    draw() 
    {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

        this.drawGrid();
        this.apple.draw();
        this.snake.draw();
    }

    update() 
    {
        this.snake.update();
    }

    loop() {
        this.update();
        this.draw();
    }
}
new Game(document.getElementById('myCanvas'), 8)

The HTML:

<!DOCTYPE html>
<html>
    <head>
        <title>test</title>
    </head>
    <body>
        <canvas id="myCanvas" width="640" height="640"></canvas>
        <script  type="text/javascript" src="https://codereview.stackexchange.com/main.js"></script>
    </body>
</html>

Snake with rust + SFML

I'm new to Rust, I basically started learning it yesterday. I have a lot of experience in other programming languages ​​and I have basically been trying to understand the basics of how to do things in Rust by coding a simple Snake game.

It would be nice to get a review / criticism for this.

I wasn't sure exactly what I was doing with regard to shelf life / property and when it is necessary to use &.

Coded:

use rand::*;
use sfml::graphics::*;
use sfml::window::*;
use sfml::system::*;
use std::collections::LinkedList;

const FIELD_SIZE : u32 = 40;
const TILE_SIZE : u32 = 15;

enum Dir 
{
    UP, 
    LEFT,
    RIGHT,  
    DOWN
}

struct Game<'g> 
{
    window : RenderWindow,
    gameover : bool,    
    dir : Dir,  
    tickrate : Time,
    rect : RectangleShape<'g>,
    food : (i32,i32),
    snake : LinkedList<(i32,i32)>
}

fn calc_tile_pos(i: i32) -> f32 
{
    return (i * TILE_SIZE as i32) as f32;
}

fn calc_random_pos() -> (i32,i32) 
{
    let mut rnd = rand::thread_rng();

    let x = rnd.gen_range(0,FIELD_SIZE as i32);
    let y = rnd.gen_range(0,FIELD_SIZE as i32);

    return (x,y);
}

fn is_in_bounds(pos : (i32,i32)) -> bool 
{
    let bounds_x = pos.0 >= 0 && pos.0 <= FIELD_SIZE as i32;
    let bounds_y = pos.1 >= 0 && pos.1 <= FIELD_SIZE as i32;

    return bounds_x && bounds_y;
}

impl<'g> Game<'g> 
{
    pub fn new() -> Self 
    {
        Self {
            dir : Dir::RIGHT,
            snake : LinkedList::new(),
            food : (20,20),
            gameover : false,
            tickrate : Time::milliseconds(150),
            rect : RectangleShape::with_size(Vector2f::new(TILE_SIZE as f32, TILE_SIZE as f32)),
            window : RenderWindow::new(
                (FIELD_SIZE * TILE_SIZE, FIELD_SIZE * TILE_SIZE), 
                "Snake", 
                Style::CLOSE, 
                &ContextSettings::default()
            ),          
        }
    }

    pub fn run(&mut self) 
    {
        self.snake.push_back((13,10));
        self.snake.push_back((12,10));
        self.snake.push_back((11,10));
        self.snake.push_back((10,10));      

        while self.window.is_open() && !self.gameover
        {   
            let time = Clock::start();

            while let Some(event) = self.window.poll_event()
            {
                match event 
                {
                    Event::Closed => return,
                    Event::KeyPressed { code: Key::Left, ..} => self.dir = Dir::LEFT,
                    Event::KeyPressed { code: Key::Right, ..} => self.dir = Dir::RIGHT,
                    Event::KeyPressed { code: Key::Up, ..} => self.dir = Dir::UP,
                    Event::KeyPressed { code: Key::Down, ..} => self.dir = Dir::DOWN,
                    Event::KeyPressed { code: Key::Escape, ..} => return,
                    _ => continue
                }
            }               

            self.tick();
            self.draw();

            // wait until next tick
            while time.elapsed_time() < self.tickrate 
            {
                sleep(Time::milliseconds(50));
            }
        }
    }   

    fn draw(&mut self) 
    {
        self.window.clear(Color::rgb(50, 50, 50));

        // calc tilepos
        let food_x = calc_tile_pos(self.food.0);
        let food_y = calc_tile_pos(self.food.1);

        self.rect.set_position(Vector2f::new(food_x, food_y));
        self.rect.set_fill_color(Color::RED);
        self.window.draw(&self.rect);

        // draw snake
        self.rect.set_fill_color(Color::GREEN);

        for element in &self.snake 
        {
            let el_x = calc_tile_pos(element.0);
            let el_y = calc_tile_pos(element.1);

            self.rect.set_position(Vector2f::new(el_x, el_y));
            self.window.draw(&self.rect);
        }       

        self.window.display();
    }


    fn tick(&mut self)
    {
        let head = self.snake.front().unwrap();

        let mut new_head = (head.0, head.1);

        match self.dir 
        {
            Dir::LEFT => new_head.0 -= 1,
            Dir::RIGHT => new_head.0 += 1,
            Dir::UP => new_head.1 -= 1,
            Dir::DOWN => new_head.1 += 1
        }       

        if self.snake.contains(&new_head) || !is_in_bounds(new_head)
        {
            self.gameover = true;
            return;
        }

        self.snake.push_front(new_head);

        if new_head == self.food
        {
            while self.snake.contains(&self.food)
            {
                self.food = calc_random_pos();
            }
        } 
        else 
        {
            self.snake.pop_back();
        }       
    }
}

fn main() 
{
    let mut game = Game::new();

    game.run(); 
}

Cargo.toml:

(package)
name = "test"
version = "0.1.0"
edition = "2018"

(dependencies)
sfml = "*"
rand = "*"

((bin))
name = "snake"
path = "Source/Snake.rs"

javascript – how to join the snake body in a 2D snake game

I'm making a snake game in javaScript from scratch. The problem is that the snake seems disjointed (see image). How can I connect the body (rectangles) of the snake?

here is the snake drawing code:

    paintSnake(margin) {
    //draws the body of the snake
    this.snake.forEach((egg) => {
      //console.log(egg)
      const isSnakeHead = egg.cellX === this.headCellX && egg.cellY === this.headCellY
      if (!isSnakeHead) {
        this.ctx.fillStyle = "#9ef739"
        this.ctx.fillRect(egg.cellX * this.cellSize + margin,
          egg.cellY * this.cellSize + margin,
          this.cellSize - 2 * margin,
          this.cellSize - 2 * margin)
      }
    })
    //snake head
    // this.ctx.beginPath()
    // this.ctx.lineWidth = 4
    // this.ctx.strokeStyle = "red"
    // this.ctx.rect(this.headCellX * this.cellSize + margin, this.headCellY * this.cellSize + margin, this.cellSize - 2 * margin, this.cellSize - 2 * margin)
    // this.ctx.stroke()
    let head =
    {
      X: this.headCellX * this.cellSize + margin,
      Y: this.headCellY * this.cellSize + margin,
      width: this.cellSize,
      height: this.cellSize
    }

    const args = (head.X,
    head.Y,
    head.height,
    head.width)
    //draw the head of the snake
    if (this.direction === "up") {
      this.ctx.drawImage(
        snakeHeadUpImg,
        ...args)
    }
    else if (this.direction === "down") {
      this.ctx.drawImage(
        snakeHeadDownImg,
        ...args)
    }
    else if (this.direction === "right") {
      this.ctx.drawImage(
        snakeHeadRightImg,
        ...args)
    }
    else if (this.direction === "left") {
      this.ctx.drawImage(
        snakeHeadLeftImg,
        ...args)
    }
  }
}

to see all the code, go to: https://github.com/hackasaur/snake-game/blob/master/main.js

snake

I know the rectangles (body parts) should be extended in the direction of the next rectangle, but how can I do this?

Snake game in the terminal, written in Python

I recently wrote a snake game. I wanted to keep it in a pure terminal, without libraries like pygame, tkinter or curses. It works fine, but I know the code could be improved. I am a rather junior programmer, and this is my first attempt at & # 39; gamedev & # 39;, because currently I am learning Django. I would be grateful if you would tell me what I should change πŸ™‚ Here is my code:

#!/usr/bin/python3
import random
import time
import keyboard
import collections


class Board:
    def __init__(self, width: int, height: int, speed: float):
        self.WIDTH = width
        self.HEIGHT = height
        self.SPEED = speed
        self.board = self.__create_board()

    def __create_board(self) -> list:
        return (("β–‘" for _ in range(self.WIDTH)) for _ in range(self.HEIGHT))

    def print_board(self) -> None:
        print('n')
        for row in self.board:
            print(row)


class Snake:
    def __init__(self, x_pos, y_pos):
        self.x_pos = x_pos
        self.y_pos = y_pos
        self.head_pos = (self.x_pos, self.y_pos)

        self.body_segments = collections.deque()  # doubly end operations, faster than lists
        self.length = 0
        self.apple_pos = (0, 0)
        self.coords = (0, 0)
        self.ate = False
        self.direction = 'up'
        self.spawn_apple()

    def set_empty_square(self) -> None:
        board_obj.board(self.y_pos)(self.x_pos) = "β–‘"

    def set_head(self) -> None:
        board_obj.board(self.y_pos)(self.x_pos) = "β– "

    def draw_body(self) -> None:
        self.body_segments.appendleft(self.coords)
        board_obj.board(self.body_segments(0)(1))(self.body_segments(0)(0)) = "&"
        if not self.ate:
            board_obj.board(self.body_segments(self.length)(1))(self.body_segments(self.length)(0)) = "β–‘"
            self.set_head()
            self.body_segments.pop()

    def move(self) -> None:
        self.coords = (self.x_pos, self.y_pos)
        self.set_empty_square()

        if self.direction == "right":
            self.x_pos += 1
        if self.direction == "left":
            self.x_pos -= 1
        if self.direction == "up":
            self.y_pos -= 1
        if self.direction == "down":
            self.y_pos += 1

        self.set_head()
        if self.length >= 1:
            self.draw_body()

        self.head_pos = (self.x_pos, self.y_pos)

    def spawn_apple(self) -> None:
        x = random.randint(0, board_obj.WIDTH-2)
        y = random.randint(0, board_obj.HEIGHT-2)
        apple_pos = (x, y)
        if apple_pos in self.body_segments or apple_pos == self.head_pos:
            self.spawn_apple()  # if apple spawned in snake, then run func again with recursion and quit current func
            return
        self.apple_pos = (x, y)
        board_obj.board(y)(x) = "●"

    def eat_apple(self) -> None:
        self.length += 1
        self.ate = True

    def collision(self) -> bool:
        return self.head_pos in self.body_segments or self.y_pos in (board_obj.HEIGHT-1, -1) 
                or self.x_pos in (board_obj.WIDTH-1, -1)


def on_press(_: None):
    for code in keyboard._pressed_events:
        if code == 105:
            snake.direction = 'left'
        elif code == 106:
            snake.direction = 'right'
        elif code == 103:
            snake.direction = 'up'
        elif code == 108:
            snake.direction = 'down'


def start_game(snake: Snake, board_obj: Board):
    snake.set_head()
    board_obj.print_board()
    keyboard.hook(on_press)
    while not snake.collision():
        print("SNAKE: ", snake.head_pos)
        print("BODY: ", snake.body_segments)
        print("APPLE: ", snake.apple_pos)

        snake.move()
        board_obj.print_board()
        snake.ate = False
        if snake.head_pos == snake.apple_pos:
            snake.eat_apple()
            snake.spawn_apple()
        time.sleep(board_obj.SPEED)
    print(f"Game over! Points: {snake.length}")


if __name__ == "__main__":
    board_obj = Board(8, 8, 0.3)  # Set: width, height, speed
    snake = Snake(int(board_obj.WIDTH / 2), int(board_obj.HEIGHT / 2))  # Set: snake x and y position

    start_game(snake, board_obj)

```

Snake game with C and SDL using linked lists

I'm totally new to C and after reading chapter 5 of K&R, I felt ready to at least make a simple game using C. I know linked lists, so since I was doing Snake implementation, why not?

main.h

#include 

#ifndef MAIN
#define MAIN

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

SDL_Renderer *getRenderer();

void quit_game(void); 
void set_freeze(bool);

#endif

main c

#include 
#include 
#include "main.h"
#include "snake.h"
#include "apple.h"

void handle_events(SDL_Event* e);
void quit(void);

SDL_Window *window;
SDL_Renderer *renderer;

bool running = false;
bool frozen = false;

bool init(void){
    bool success = true;
    window = NULL;
    renderer = NULL;

    if(SDL_Init(SDL_INIT_VIDEO) < 0){
        printf("SDL could not be initiliazed. SDL_Error: %sn", SDL_GetError());
        success = false;
    }

    window = SDL_CreateWindow("snake game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
    if(!window){
        printf("SDL_Window could not be initialized. SDL_Error: %sn", SDL_GetError());
        success = false;
    }
    else{
        renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);    
    }

    if(!init_snake()){
        printf("snake could not be initialized.n");
        success = false;
    }

    generate_new_apple_pos();

    running = true;
    return success;
}

int main(int argc, char* args())
{
    if(!init())
        return -1;
    else{
        SDL_Event e;

        while(running){
            handle_events(&e);

            if(frozen)
                continue;

            SDL_SetRenderDrawColor(renderer, 255, 255, 224, SDL_ALPHA_OPAQUE);
            SDL_RenderClear(renderer);

            update_snake();
            render_apple();

            SDL_RenderPresent(renderer);

            SDL_Delay(50);
        }
    }

    quit_game();
    return 0;
}

void handle_events(SDL_Event *e)
{
    while(SDL_PollEvent(e) != 0){
        if((*e).type == SDL_QUIT){
            running = false;
        }
        else if((*e).type == SDL_KEYDOWN){
            switch((*e).key.keysym.sym){
                case SDLK_RIGHT:
                    change_snake_direction(RIGHT);
                    break;
                case SDLK_LEFT:
                    change_snake_direction(LEFT);
                    break;
                case SDLK_UP:
                    change_snake_direction(UP);
                    break;
                case SDLK_DOWN:
                    change_snake_direction(DOWN);
                    break;
            }
        }
    }
}

void quit_game(void){
    SDL_DestroyWindow(window);
    window = NULL;

    SDL_DestroyRenderer(renderer);
    renderer = NULL;

    free_tails();
    SDL_Quit();
}

void set_freeze(bool b)
{
    frozen = b;
}

SDL_Renderer* getRenderer() { return renderer; }

snake.h

#include 
#ifndef SNAKE
#define SNAKE

static const int DEFAULT_X = 500;
static const int DEFAULT_Y = 10;
static const int DEFAULT_WIDTH = 20;
static const int DEFAULT_HEIGHT = 20;

static const int DEFAULT_TAILS_N = 10;

struct TailNode{
    SDL_Rect rect;
    struct TailNode *next;
    struct TailNode *previous;
};

struct Snake{
    int dx;
    int dy;
    int size;
    struct TailNode head;
};

enum direction{LEFT, RIGHT, UP, DOWN};

bool init_snake(void);
void update_snake(void);
void change_snake_direction(int);
void free_tails(void);

#endif

snake.c

#include 
#include 
#include 
#include "snake.h"
#include "main.h"
#include "apple.h"

struct Snake snake;
struct TailNode *lasttail;

void push_tail();

bool init_snake()
{
    // default direction
    snake.dx = -1;
    snake.dy = 0;

    // initializes head
    snake.head.rect.x = DEFAULT_X;
    snake.head.rect.y = DEFAULT_Y;
    snake.head.rect.w = DEFAULT_WIDTH;
    snake.head.rect.h = DEFAULT_HEIGHT;
    snake.head.next = NULL;
    snake.head.previous = NULL;

    // sets pointer of last tail to head
    lasttail = &snake.head;

    // pushes default tails
    for(int i = 0; i < DEFAULT_TAILS_N; ++i)
        push_tail();

    return true;
}


void render_tail(SDL_Rect *tail)
{   // renders individual parts of the snake
    SDL_SetRenderDrawColor(getRenderer(), 204, 175, 175, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(getRenderer(), tail);
}

void check_collision()
{
    // fruit collision
    if(abs(snake.head.rect.x - get_apple_posX()) < DEFAULT_WIDTH && abs(snake.head.rect.y - get_apple_posY()) < DEFAULT_HEIGHT){
        push_tail();
        generate_new_apple_pos();
    }

    // border collision
    if(snake.head.rect.x > SCREEN_WIDTH - DEFAULT_WIDTH)
        snake.head.rect.x = 0;
    else if(snake.head.rect.x < 0 - DEFAULT_WIDTH)
        snake.head.rect.x = SCREEN_WIDTH;
    else if(snake.head.rect.y < 0 - DEFAULT_HEIGHT)
        snake.head.rect.y = SCREEN_HEIGHT;
    else if(snake.head.rect.y > SCREEN_HEIGHT - DEFAULT_HEIGHT)
        snake.head.rect.y = 0;
}

void update_snake(void)
{   // iterates over the head and the tail
    for(struct TailNode *ptr = lasttail; ptr != NULL; ptr = (*ptr).previous){
        if((*ptr).previous == NULL){ // in other words, if this "tail" is the head
            snake.head.rect.x += snake.dx * DEFAULT_WIDTH;
            snake.head.rect.y += snake.dy * DEFAULT_HEIGHT;
        }else{ // if it's the snake's body
            if(abs(snake.head.rect.x - (*ptr).rect.x) < DEFAULT_WIDTH && // checks collision with the head
               abs(snake.head.rect.y - (*ptr).rect.y) < DEFAULT_HEIGHT)
                set_freeze(true);

            (*ptr).rect.x = (*ptr).previous->rect.x;
            (*ptr).rect.y = (*ptr).previous->rect.y;
        }

        render_tail(&(*ptr).rect);
    }

    check_collision(); // head-only collision (fruit, border, etc.)
}

void push_tail()
{   // pushes a new tail inside the linked list
    struct TailNode *new_tail = malloc(sizeof(struct TailNode));
    if(new_tail == NULL) 
        quit_game();

    (*new_tail).rect.x = (*lasttail).rect.x + 30;
    (*new_tail).rect.y = (*lasttail).rect.y;
    (*new_tail).rect.w = DEFAULT_WIDTH;
    (*new_tail).rect.h = DEFAULT_HEIGHT;

    (*new_tail).next = NULL;
    (*new_tail).previous = lasttail;

    (*lasttail).next = new_tail;
    lasttail = new_tail;
}

void change_snake_direction(int dir)
{
    if(dir == RIGHT && snake.dx != -1){
        snake.dx = 1;
        snake.dy = 0;
    }
    else if(dir == LEFT && snake.dx != 1){
        snake.dx = -1;
        snake.dy = 0;
    }
    else if(dir == UP && snake.dy != 1){
        snake.dy = -1;
        snake.dx = 0;
    }
    else if(dir == DOWN && snake.dy != -1){
        snake.dy = 1;
        snake.dx = 0;
    }
}

void free_tails()
{
    struct TailNode *tmp;
    struct TailNode *secondtail;
    secondtail = snake.head.next; // we skip the first node (head) because it's allocated in the stack

    while(secondtail != NULL){
        tmp = secondtail;
        secondtail = (*secondtail).next;
        free(tmp);
    }
}

apple.h

#ifndef APPLE
#define APPLE

static const int DEFAULT_APPLE_WIDTH = 20;
static const int DEFAULT_APPLE_HEIGHT = 20;

void render_apple(void);
void generate_new_apple_pos(void);

int get_apple_posX(void);
int get_apple_posY(void);

#endif

apple.c

#include 
#include 
#include "main.h"
#include "apple.h"

SDL_Rect apple;

void generate_new_apple_pos(void);

void render_apple()
{
    SDL_SetRenderDrawColor(getRenderer(), 226, 106, 106, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(getRenderer(), &apple);
}

void generate_new_apple_pos(void)
{
    apple.x = (rand() % (SCREEN_WIDTH - 0 + 1));
    apple.y = (rand() % (SCREEN_HEIGHT - DEFAULT_APPLE_HEIGHT + 1));
    apple.w = DEFAULT_APPLE_WIDTH;
    apple.h = DEFAULT_APPLE_HEIGHT;
}

int get_apple_posX(void)
{
    return apple.x;
}
int get_apple_posY(void)
{
    return apple.y;
}

ALL suggestions and tips for improving this code are welcome, I am trying to improve my fundamentals so that I can develop bigger projects in C.

A few questions, however:

  1. Am I using the headers correctly? Or is it a mess? What can i do for
    improve the organization?

  2. Is my implementation of a linked list correct?

  3. the snakeit is dx and dy the values ​​are 1, 0 or -1. Should i make one short instead? Or even char?

  4. How can I do struct TailNode private to snake.c?

  5. When should i use static const on macro #defines? Do I have to use static const when i want my variable to be private?

Thank you!

handle – Missing pendulum snake models

guys!

I wanted to make a pendulum simulation and be able to reproduce the patterns that are created by creating several pendulums at the same time. But for some reason, after the first few seconds, I can't see them. I tried to replicate something similar to Berger Dillon's pendulum on Twitter, Pendulum serpent – Berger Dillon. My script is shown below, but something seems a little offbeat. I really don't know what it could be. Thank you!

g = 9.81;
initialAngle = (Pi)/4;
nSpheres = 10;
radius = 1;
initialLength = 5;
time = 300;
timeStep = 0.25;

sol2(l_) := (Theta) /. 
   NDSolve({(Theta)''(t) + g/l (Theta)(t) == 0, (Theta)(0) == 
      initialAngle, (Theta)'(0) == 0}, (Theta), {t, 0, 1000}) // 
  First

timeList = Table(i, {i, 0, time, timeStep});
xPos = Table(i, {i, 1, nSpheres});

pos = Table(
  Map((l + initialLength) {Sin(
       sol2(l + initialLength)(#1)), -Cos(
        sol2(l + initialLength)(#1))} &, timeList), {l, 0, 
   nSpheres - 1});

spheres(t_) := 
 Table(Table(
     Graphics3D({Hue(1/i), 
       Sphere(Join(pos((i, t + 1)), {x}), radius)}), {i, 1, 
      nSpheres})((j)) /. x -> xPos((j)), {j, 1, Length(xPos)})

lines(t_) := 
 Table(Table(
     Graphics3D({White, 
       Line({{0, 0, x}, Join(pos((i, t + 1)), {x})})}), {i, 1, 
      nSpheres})((j)) /. x -> xPos((j)), {j, 1, Length(xPos)})

Manipulate(
 Show({lines(t), spheres(t)}, ViewPoint -> {0, 0, -2}, 
  Background -> Black, Boxed -> True, 
  PlotRange -> {{-15, 15}, {-15, 10}, {-5, 15}}), {t, 0, 
  Length(pos((1))) - 1, 1})

Snake, Minesweeper and Tetris made in C ++ & OpenGL

In the past 2 months, I have recreated Snake, Minesweeper and Tetris in C ++ using the OpenGL specification. Each program contains only the basic game and nothing more. No user interface, no text, no user settings, just the game. Game More than ends the program (exception: Minesweeper & # 39; R & # 39; resets the card).

I used GLFW to create windows, OpenGL handles and receive input. I used GLAD as the OpenGL and OpenGL Mathematics (GLM) load library for operations on matrices.

https://github.com/SavariaS/Snake Snake

https://github.com/SavariaS/Minesweeper Minesweeper

https://github.com/SavariaS/Tetris Tetris

OpenGL is my first experience with graphics programming. These are the first programs that I have developed myself using the OpenGL specification and some of the larger C ++ programs that I have created so far. I had help designing the OpenGL objects and making them work but all the C ++ code and the structure of the game belong to me.

I'm looking for feedback on my implementation of OpenGL. The tutorial I am reading to learn OpenGL (learnopengl) does a good job of teaching theory but he said that their code examples are ineffective and do not represent how one would normally code for OpenGL. So, I'm looking for ways to make my code more efficient and better manage OpenGL objects. I'm also looking for ways to implement sprite sheets and 2D animations (both present in Tetris).

Finally, I'm looking for feedback on my use of C ++ and the structure of my code. I'm a bit experienced in C ++ but I'm still looking for ways to improve my code. It is also the first time that I have developed a game structure and a game loop and I would like to know how most people conceive of it. Comments on my use of OOP and code division are also welcome.

python – Pygame snake as first game

After delving into some areas of python, I decided to try Pygame. After about two hours of coding, here is what I found:

import pygame
import time
import random
pygame.init()
pygame.font.init()

WINDOW = pygame.display.set_mode((500, 500))

pygame.display.set_caption('snake')

FOOD_COORS = ()

TICK = 15


RUN = True
SNAKE_COMP = ((50, 50, 2), (40, 50, 2), (30, 50, 2), (20, 50, 2), (10, 50, 2))
f = (random.randint(0, 50)*10, random.randint(0, 50)*10)
d = 2
CLOCK = pygame.time.Clock()

def hit():
    time.sleep(3)
    pygame.quit()

class snake():
    def __init__(self, SNAKE_COMP):
        self.x, self.y = SNAKE_COMP(0)(0:2)
    def draw(self, SNAKE_COMP):
        self.SNAKE_COMP = SNAKE_COMP
        for i in range(0, len(SNAKE_COMP)):
            pygame.draw.rect(WINDOW, (255, 255, 255), (SNAKE_COMP(i)(0), SNAKE_COMP(i)(1), 10, 10))

    def hit_check(self, SNAKE_COMP):
        self.SNAKE_COMP = SNAKE_COMP
        if SNAKE_COMP(0)(0) >= 500 or SNAKE_COMP(0)(0) < 0:
            hit()
        if SNAKE_COMP(0)(1) >= 500 or SNAKE_COMP(0)(1) < 0:
            hit()
        test_l = (())
        for i in range(0, len(SNAKE_COMP)):
            test_l.append(tuple(SNAKE_COMP(i)(0:2)))
        for i in range(0, len(test_l)):
            if test_l.count(test_l(i)) > 1:
                hit()

class food():
    global FOOD_COORS
    def draw(self):
        x, y = self.x, self.y
        pygame.draw.rect(WINDOW, (255, 255, 255), (x, y, 10, 10))
    def spawn(self, SNAKE_COMP):
        global FOOD_COORS
        self.SNAKE_COMP = SNAKE_COMP
        test_l = (())
        for i in range(0, len(SNAKE_COMP)):
            test_l.append(SNAKE_COMP(i)(0:2))
        g = True
        while g:
            x = random.randint(0, 49)*10
            y = random.randint(0, 49)*10
            if (x, y) not in test_l:
                g = False
        FOOD_COORS = (x, y)
        self.x, self.y = x, y
snek = snake(SNAKE_COMP)
apple = food()
apple.spawn(SNAKE_COMP)
s = False
g = False
while RUN:
    CLOCK.tick(TICK)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            RUN = False

    keys = pygame.key.get_pressed()
    if keys(pygame.K_UP) and d != 3:
        d = 1
    elif keys(pygame.K_RIGHT) and d != 4:
        d = 2
    elif keys(pygame.K_DOWN) and d != 1:
        d = 3
    elif keys(pygame.K_LEFT) and d != 2:
        d = 4
    if g != True and SNAKE_COMP(0)(0:2) != FOOD_COORS:
        last = len(SNAKE_COMP) - 1
        for i in range(1, len(SNAKE_COMP)):
            SNAKE_COMP(len(SNAKE_COMP)-i)(2) = SNAKE_COMP(len(SNAKE_COMP)-i-1)(2)
        SNAKE_COMP(0)(2) = d
        for i in range(0, len(SNAKE_COMP)):
            if SNAKE_COMP(i)(2) == 1:
                SNAKE_COMP(i)(1) -= 10
            elif SNAKE_COMP(i)(2) == 2:
                SNAKE_COMP(i)(0) += 10
            elif SNAKE_COMP(i)(2) == 3:
                SNAKE_COMP(i)(1) += 10
            elif SNAKE_COMP(i)(2) == 4:
                SNAKE_COMP(i)(0) -= 10
    else:
        k = SNAKE_COMP(0)(2)
        FOOD_COORS.append(k)
        if k == 1:
            FOOD_COORS(1) -= 10
        elif k == 2:
            FOOD_COORS(0) += 10
        elif k == 3:
            FOOD_COORS(1) += 10
        elif k == 4:
            FOOD_COORS(0) -= 10
        SNAKE_COMP.insert(0, FOOD_COORS)
        apple.spawn(SNAKE_COMP)
    snek.hit_check(SNAKE_COMP)
    apple.draw()
    snek.draw(SNAKE_COMP)
    pygame.display.update()
    WINDOW.fill((0, 0, 0))

pygame.quit()

I really think it can be improved, but I don't know how.

unit – Snake tail in Snake game is not working properly

I make a simple snake game in Unity 2D. And the snake tail doesn't follow just behind the snake head as it should.

This is what is happening: https://imgur.com/a/zG6hbd7

Here is my code:

using System.Collections;

using System.Collections.Generic;
using UnityEngine;
using System.Linq;

Public class SnakeMovement class: MonoBehavior
{

private Vector3 fp;   //First touch position
private Vector3 lp;   //Last touch position

private float dragDistance;  //minimum distance for a swipe to be registered
private float speed = 13f;

private Rigidbody2D rb;
private Vector2 moveVelocity;

public GameObject tail;

public List tailPositions;

void Start() {
    dragDistance = Screen.height * 5 / 100; //dragDistance is 5% height of the screen
    rb = GetComponent();
}

void Update() {

    if (Input.touchCount == 1) // user is touching the screen with a single touch
    {
        Touch touch = Input.GetTouch(0); // get the touch
        if (touch.phase == TouchPhase.Began) //check for the first touch
        {
            fp = touch.position;
            lp = touch.position;
        }
        else if (touch.phase == TouchPhase.Moved) // update the last position based on where they moved
        {
            lp = touch.position;
        }
        else if (touch.phase == TouchPhase.Ended) //check if the finger is removed from the screen
        {
            lp = touch.position;  //last touch position. Ommitted if you use list

            //Check if drag distance is greater than ?% of the screen height
            if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
            {//It's a drag
             //check if the drag is vertical or horizontal

                if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y)) {   //If the horizontal movement is greater than the vertical movement...
                    if ((lp.x > fp.x)) {   //Right swipe
                        if(moveVelocity != Vector2.left) {
                            moveVelocity = Vector2.right;
                        }
                    }
                    else {   //Left swipe
                        if(moveVelocity != Vector2.right) {
                            moveVelocity = Vector2.left;
                        }
                    }
                }
                else {   //the vertical movement is greater than the horizontal movement
                    if (lp.y > fp.y) {   //Up swipe
                        if(moveVelocity != Vector2.down) {
                            moveVelocity = Vector2.up;
                        }
                    }
                    else {   //Down swipe
                        if(moveVelocity != Vector2.up) {
                            moveVelocity = Vector2.down;
                        }
                    }
                }

            }
        }
    }

}

void FixedUpdate() {
    Vector3 lastPos = transform.position;

    rb.MovePosition(rb.position + moveVelocity * speed * Time.deltaTime);

    if (tailPositions.Count >= 1) {
        tailPositions.Last().position = lastPos;
        tailPositions.Insert(0, tailPositions.Last ());
        tailPositions.RemoveAt(tailPositions.Count - 1);
    }
}

void OnTriggerEnter2D(Collider2D trigger) {
    Vector2 spawnPos = new Vector2(5, 5);

    if (trigger.tag == "Food") {
        GameObject newTail = Instantiate(tail, spawnPos, Quaternion.identity) as GameObject;
        newTail.transform.parent = GameObject.Find("Tail Holder").transform;
        tailPositions.Add(newTail.transform);
    }
}

}

Thank you very much for taking the time to help me.