Posts: 9
Threads: 3
Joined: Oct 2024
I'll post more code if needed, but I'm a bit confused. I'm currently using pygame for this.
I use randint() to spawn objects at random intervals, and then after that, move them in a random direction (up, down, left or right) at a different random interval. My problem is that with how I've coded it, the objects snap/teleport whatever the distance is, rather than move there at a fast speed that I set. I can't seem to figure out how to make them move gradually to a random destination.
# directions for the enemy object to move in
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
# spawn an enemy in a random spot
def spawn_enemy_object():
x = randint(0, window.get_width() - object_size)
y = randint(0, window.get_height() - object_size)
enemy_direction = choice(directions)
return {
'rect': pygame.Rect(x, y, object_size, object_size),
'enemy_direction': enemy_direction,
'enemy_move_time': pygame.time.get_ticks() + randint(5000, 8000),
'enemy_moves_left': 2,
'is_enemy_moving': True, # start moving
'speed': 50 # speed of the enemy rectangle object
}
elif event.type == move_event:
current_time = pygame.time.get_ticks()
for obj in objects[:]:
if current_time >= obj['enemy_move_time']:
if obj['is_enemy_moving']:
if obj['enemy_moves_left'] > 0:
obj['rect'].x += obj['enemy_direction'][0] * obj['speed']
obj['rect'].y += obj['enemy_direction'][1] * obj['speed']
obj['enemy_move_time'] = current_time + randint(5000, 9000)
obj['enemy_moves_left'] -= 1
else: This was my final attempt. My previous attempt was much more basic, but there was no difference unfortunately.
Posts: 1,144
Threads: 114
Joined: Sep 2019
Oct-21-2024, 07:38 AM
(This post was last modified: Oct-21-2024, 07:38 AM by menator01.)
I don't know what the rest of your code looks like but, here is a basic example of pygame animation.
A red ball bouncing off of the walls.
Added comments and added ability to increase or decrease speed using keypad + or minus key.
Speed will increase or decrease after bounce. The r key will reset default speed.
import pygame
from random import choice
pygame.init()
pygame.font.init()
font = pygame.font.SysFont(None, 28)
screen_width, screen_height = (1280, 740)
screen = pygame.display.set_mode((1280,740))
clock = pygame.time.Clock()
running = True
# Create a sprite group to update sprites on the screen
allsprites = pygame.sprite.Group()
text_sprites = pygame.sprite.Group()
instruct_sprites = pygame.sprite.Group()
ball_sprites = pygame.sprite.Group()
class Ball(pygame.sprite.Sprite):
''' Mob class creates a red ball '''
def __init__(self, screen_width, screen_height):
pygame.sprite.Sprite.__init__(self)
# Create a surface
self.image = pygame.Surface((50,50))
self.image.fill('black')
self.image.set_colorkey('black')
# Get surface rect
self.rect = self.image.get_rect()
# Starting position - center of screen
self.rect.centerx = screen_width/2
self.rect.centery = screen_height/2
# Set instance variables
self.screen_width = screen_width
self.screen_height = screen_height
# Size of the ball
size = (25, 25)
# Radius of ball
radius = 25
# Draw the ball on the surface
pygame.draw.circle(self.image, 'red', size, radius)
# Set a speed
self.speed = 8
# Set x and y speed
self.speed_x = self.speed
self.speed_y = self.speed
# Blit image to screen
screen.blit(self.image, self.rect)
# Add ball to sprite group
allsprites.add(self)
ball_sprites.add(self)
def update(self):
''' Method for updating ball position '''
# If ball reaches screen with - minus speed to go in other direction towards 0
if self.rect.right >= self.screen_width:
self.speed_x = -self.speed
# If ball reaches 0 position add positive speed for ball go in other direction towards screen width
if self.rect.left <= 0:
self.speed_x = self.speed
# If ball reaches top of screen (0 position) add positive speed to go down
if self.rect.top <= 0:
self.speed_y = self.speed
# If ball reaches screen height, add negative speed to go up toward 0 position
if self.rect.bottom >= self.screen_height:
self.speed_y = -self.speed
# Update ball position
self.rect.centerx += self.speed_x
self.rect.centery += self.speed_y
class MyText(pygame.sprite.Sprite):
def __init__(self, text, x, y, width, height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((width, height))
self.image.fill('#555555')
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
self.msg = text
self.text = font.render(self.msg, True, 'white')
self.image.blit(self.text, (10,5))
# Create a ball object
ball = Ball(screen_width, screen_height)
# Create the speed text object
speedtext = MyText(f'Speed: {ball.speed}', 0, 0, 200, 30)
# Create the instructions text object
text = 'keypad + = increase speed, keypad - = decrease speed, key r = reset speed'
instructions = MyText(text, screen_width-720, screen_height-30, 720, 30)
# Add to sprite groups
allsprites.add(speedtext)
text_sprites.add(speedtext)
allsprites.add(instructions)
instruct_sprites.add(instructions)
while running:
screen.fill('black')
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If event type is key press
if event.type == pygame.KEYDOWN:
# Get the key pressed. + plus key increase speed by 1
# Minus key decrease speed by 1
# r key reset default speed
if event.key == pygame.K_KP_PLUS:
ball.speed += 1
if ball.speed >= 25:
ball.speed = 25
if event.key == pygame.K_KP_MINUS:
ball.speed -= 1
if ball.speed <= 2:
ball.speed = 2
if event.key == pygame.K_r:
ball.speed = 8
# This is to empty the sprite groups of the object speed text
# so we are not piling on sprite after sprite after sprite
text_sprites.empty()
allsprites.remove(speedtext)
# Create new text with updated speed value and add to sprite groups
speedtext = MyText(f'Speed: {ball.speed}', 0, 0, 200, 30)
text_sprites.add(speedtext)
allsprites.add(speedtext)
# Detect collissions with the text boxes
if pygame.sprite.groupcollide(ball_sprites, text_sprites, False, False):
ball.speed_y = ball.speed
if pygame.sprite.groupcollide(ball_sprites, instruct_sprites, False, False):
ball.speed_y = -ball.speed
# Update and draw all sprites
allsprites.update()
allsprites.draw(screen)
pygame.display.update()
# Set a frame rate. If you don't have this the speed is very fast
clock.tick(60)
pygame.quit()
Posts: 1,144
Threads: 114
Joined: Sep 2019
Just wanted to add one more way that doesn't use sprites. I prefer sprites as it makes collision detection easier.
import pygame
from pygame import gfxdraw
running = True
window_size = (1280,740)
screen = pygame.display.set_mode(window_size)
clock = pygame.time.Clock()
fps = 60
screen_width, screen_height = screen.get_size()
# Colors
BLACK = pygame.Color(0, 0, 0)
WHITE = pygame.Color(255, 255, 255)
RED = pygame.Color(255, 0, 0)
GREEN = pygame.Color(0, 255, 0)
BLUE = pygame.Color(0, 0, 255)
ORANGE = pygame.Color(255, 127, 0)
PURPLE = pygame.Color(255, 0, 255)
CYAN = pygame.Color(0, 255, 255)
pygame.init()
class Ball:
''' Ball class will draw a ball object '''
def __init__(self, screen):
# Set starting instance variables
self.x = screen_width/2
self.y = screen_height/2
self.radius = 25
self.speed = 8
self.speed_x = self.speed
self.speed_y = self.speed
self.color = GREEN
def update(self):
''' Method for updating ball position. Also chamges ball colors on wall impact '''
if self.x <= 0 + (self.radius/2+self.radius*0.5):
self.speed_x = self.speed
self.color = RED
if self.x >= screen_width-(self.radius/2+self.radius*0.5):
self.speed_x = -self.speed
self.color = CYAN
if self.y <= 0 + (self.radius/2+self.radius*0.5):
self.speed_y = self.speed
self.color = WHITE
if self.y >= screen_height-(self.radius/2+self.radius*0.5):
self.speed_y = -self.speed
self.color = GREEN
self.x += self.speed_x
self.y += self.speed_y
def draw(self, screen):
''' Method for drawing ball on the screen '''
self.ball = pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius)
ball = Ball(screen)
while running:
screen.fill(BLACK)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Update position and draw ball
ball.update()
ball.draw(screen)
pygame.display.update()
clock.tick(fps)
pygame.quit()
Posts: 9
Threads: 3
Joined: Oct 2024
Oct-23-2024, 11:20 AM
(This post was last modified: Oct-23-2024, 11:20 AM by temlotresid6.)
(Oct-21-2024, 07:38 AM)menator01 Wrote: I don't know what the rest of your code looks like but, here is a basic example of pygame animation.
A red ball bouncing off of the walls.
Added comments and added ability to increase or decrease speed using keypad + or minus key.
Speed will increase or decrease after bounce. The r key will reset default speed.
import pygame
from random import choice
pygame.init()
pygame.font.init()
font = pygame.font.SysFont(None, 28)
screen_width, screen_height = (1280, 740)
screen = pygame.display.set_mode((1280,740))
clock = pygame.time.Clock()
running = True
# Create a sprite group to update sprites on the screen
allsprites = pygame.sprite.Group()
text_sprites = pygame.sprite.Group()
instruct_sprites = pygame.sprite.Group()
ball_sprites = pygame.sprite.Group()
class Ball(pygame.sprite.Sprite):
''' Mob class creates a red ball '''
def __init__(self, screen_width, screen_height):
pygame.sprite.Sprite.__init__(self)
# Create a surface
self.image = pygame.Surface((50,50))
self.image.fill('black')
self.image.set_colorkey('black')
# Get surface rect
self.rect = self.image.get_rect()
# Starting position - center of screen
self.rect.centerx = screen_width/2
self.rect.centery = screen_height/2
# Set instance variables
self.screen_width = screen_width
self.screen_height = screen_height
# Size of the ball
size = (25, 25)
# Radius of ball
radius = 25
# Draw the ball on the surface
pygame.draw.circle(self.image, 'red', size, radius)
# Set a speed
self.speed = 8
# Set x and y speed
self.speed_x = self.speed
self.speed_y = self.speed
# Blit image to screen
screen.blit(self.image, self.rect)
# Add ball to sprite group
allsprites.add(self)
ball_sprites.add(self)
def update(self):
''' Method for updating ball position '''
# If ball reaches screen with - minus speed to go in other direction towards 0
if self.rect.right >= self.screen_width:
self.speed_x = -self.speed
# If ball reaches 0 position add positive speed for ball go in other direction towards screen width
if self.rect.left <= 0:
self.speed_x = self.speed
# If ball reaches top of screen (0 position) add positive speed to go down
if self.rect.top <= 0:
self.speed_y = self.speed
# If ball reaches screen height, add negative speed to go up toward 0 position
if self.rect.bottom >= self.screen_height:
self.speed_y = -self.speed
# Update ball position
self.rect.centerx += self.speed_x
self.rect.centery += self.speed_y
class MyText(pygame.sprite.Sprite):
def __init__(self, text, x, y, width, height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((width, height))
self.image.fill('#555555')
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
self.msg = text
self.text = font.render(self.msg, True, 'white')
self.image.blit(self.text, (10,5))
# Create a ball object
ball = Ball(screen_width, screen_height)
# Create the speed text object
speedtext = MyText(f'Speed: {ball.speed}', 0, 0, 200, 30)
# Create the instructions text object
text = 'keypad + = increase speed, keypad - = decrease speed, key r = reset speed'
instructions = MyText(text, screen_width-720, screen_height-30, 720, 30)
# Add to sprite groups
allsprites.add(speedtext)
text_sprites.add(speedtext)
allsprites.add(instructions)
instruct_sprites.add(instructions)
while running:
screen.fill('black')
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If event type is key press
if event.type == pygame.KEYDOWN:
# Get the key pressed. + plus key increase speed by 1
# Minus key decrease speed by 1
# r key reset default speed
if event.key == pygame.K_KP_PLUS:
ball.speed += 1
if ball.speed >= 25:
ball.speed = 25
if event.key == pygame.K_KP_MINUS:
ball.speed -= 1
if ball.speed <= 2:
ball.speed = 2
if event.key == pygame.K_r:
ball.speed = 8
# This is to empty the sprite groups of the object speed text
# so we are not piling on sprite after sprite after sprite
text_sprites.empty()
allsprites.remove(speedtext)
# Create new text with updated speed value and add to sprite groups
speedtext = MyText(f'Speed: {ball.speed}', 0, 0, 200, 30)
text_sprites.add(speedtext)
allsprites.add(speedtext)
# Detect collissions with the text boxes
if pygame.sprite.groupcollide(ball_sprites, text_sprites, False, False):
ball.speed_y = ball.speed
if pygame.sprite.groupcollide(ball_sprites, instruct_sprites, False, False):
ball.speed_y = -ball.speed
# Update and draw all sprites
allsprites.update()
allsprites.draw(screen)
pygame.display.update()
# Set a frame rate. If you don't have this the speed is very fast
clock.tick(60)
pygame.quit()
Thanks for the reply. I actually managed to solve this on my own by just redoing the entire code. I had to completely change every part of the code in my post that handles AI movement and now I get that smooth, gradual movement that I was trying to get. But I also tested your code and it was insightful so I appreciate it. I'm going to look into both replies of yours once I've progressed a bit more with pygame, especially when it comes to sprites.
samhatter likes this post
|