How to dynamically instantiate objects from a certain class [duplicate] - python

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 2 years ago.
I'm making a simple ball game using a 2D map. The amount of balls on the map is variable. When starting the game I load the map and look for balls (The balls are unique letters). I append these ball names to a list.
I also have a Ball class. __init__ contains the coordinates of the ball and the class contains a couple of methods.
Here comes the problem:
I want to create objects of each ball using the Ball class, with the object name corresponding to the letter belonging to the ball.
I tried this:
(The map is a txt file looking like this:)
0 0 0 0
0 0 X 0
0 A 0 B
Where the zero's represent empty tiles.
class Ball:
def __init__( self, x, y):
self.x = x
self.y = y
map_data = np.genfromtxt('map.txt', dtype=str)
ball_names = []
for row in variables.map_data:
for i in row:
if i.isalpha():
ball_names.append(i)
for ball in ball_names:
coordinates = np.where(map_data == ball)
ball = Ball(coordinates[0], coordinates[1])
But then I want the object to be named after the string contained by the variable ball, not 'ball'.
I know this can be done using exec(), but I've been told to avoid that function.

Generating variables dynamically with exec is a bad idea. As in fact variables will be totally hidden from developer. Supporting such code will be a nightmare and it's going to be a giant source of problems.
Instead, why don't you create a dict of balls?
my_balls = dict()
for ball in ball_names:
coordinates = np.where(map_data == ball)
my_balls[ball] = Ball(coordinates[0], coordinates[1])
But if you really want to create a variable, then:
exec(f'{ball} = Ball({coordinates[0]}, {coordinates[1]})')

Related

one unit snake in pygame even though its longer [duplicate]

This question already has an answer here:
How do I get the snake to grow and chain the movement of the snake's body?
(1 answer)
Closed 1 year ago.
ok so i have been playing around with pygame and python and I have already build snake but that was a very weird system and i want to build like a pathfinder for it that can path find around obstacles (the snake body) to the apple but the movement of the body is wonky and i know that sounds stupid since i cant even make snake how am I gonna make a pathfinder but i have done it before so here goes:
the snake will look like this: snake = [[1,0],[0,0]]
the direction is just stored in a tuple: direction = (xmov = 1,ymov = 0)
time += 1
if time > 30:
time = 0
snakeindex = len(snake)-1
snakeindex will be one
while snakeindex > 0:
this activates once and as far as it know it works
snake[snakeindex] = snake[snakeindex-1]
snakeindex -= 1
the snake will end up like this: [[1,0],[1,0]]
but then here:
snake[0][0] += direction[0]
snake[0][1] += direction[1]
the snake will then look like this: [[2,0],[2,0]]
Python optimization is messy sometimes for mutable objects like lists,dictionaries etc. Your snake parts is just one part, and references to this part.
You shouldn't do thing like:
a = [1,2]
b = a
# Now you might think there's to arrays
# But it's one array, and b is just a reference to a.
# If you change b or a both changes.
a[0] = 9
print(a, b)
# This will print out [9,2] and [9,2]
Use .copy() to actually copy list:
snake[snakeindex] = snake[snakeindex-1].copy()

Python Processing: How to call multiple of the same class

I am a noob at Python and I am having trouble with this problem. I am trying to create a raindrop scene with the 'drop' class. Right now, the code only calls one drop at a time. How can I call multiple drops at once?
Here is my code:
import random
class drop():
def __init__(self):
# where the drop starts
self.x = random.randint(20,480)
self.y = 0
#how fast the drop falls
self.yspeed = 5
def fall(self):
self.y = self.y+self.yspeed
def show(self):
# color of drop
stroke(1,1,1)
fill(1,1,1)
strokeWeight(1)
line(self.x,self.y,self.x,self.y+10)
def setup():
size(500,500)
global d
d = drop()
def draw():
background(255,255,255)
d.fall()
d.show()
You can create as many instances of a class as you want. For example the following code creates two drops.
d1 = drop()
d2 = drop()
You can also create a list of drops like this -
drops = []
drops.append(drop())
drops.append(drop())
drops[0].fall()
drops[1].show()
I'm a bit rusty with Python, But I would suggest changing draw to accept an array of elements.
So for example, in setup and can generate an array of droplets by doing:
def setup():
size(500,500) #Idk what this does, I assume its another function somewhere else in your code
droplets = [] #The array of droplets we want to render
for x in range(6): #6 is the number of droplets we want.
droplets.append(drop())
#Pass droplets into draw.
def draw(entities):
background(255,255,255) #Again, IDK what this does but its in your code. I assume it is another function somewhere.
for droplet in entities: #Goes through ALL the droplets in the list you passed.
droplet.fall() #Calls these methods on every droplet in the array.
droplet.show()
This is untested, but from here you would somehow pass the droplets array into draw and BOOM you have a bunch of droplets being rendered every draw cycle. I would suggest NOT using global variables. Its just bad practice. You should have another function somewhere that runs all of this, I assume on a time for the draw cycle.

Collision detection variable always output "True"? [duplicate]

This question already has answers here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
(1 answer)
How do I detect collision in pygame?
(5 answers)
Closed 2 years ago.
I apologise if you have seen a post of mine regarding this issue already, I am desperate to solve this.
I am creating a 2-player top down racing game and need to create a way for the program to know when the users have completed a lap. I have chosen to do this by placing sprites on the track, with the same texture as the track, so that they blend in. The idea is to create a list for each player's vehicle, containing boolean variables, one variable for each checkpoint. Every boolean variable in the list has to equal "True" in order for a lap to be counted.
Before I attempt this, I want to figure out how it can be done by detecting when the player's vehicles collide with each other. I have attempted, with help from a previous post, to do this.
My vehicle class can be seen, with my checkCollision function, below.
class Vehicle(pygame.sprite.Sprite):
'Base class for all vehicles (Cars and Motorbikes) in the game'
vehicleCount = 0
def __init__(self, max_speed, acceleration, turning_radius, image):
#pygame.sprite.Sprite.__init__(self)
self.max_speed = max_speed
self.acceleration = acceleration
self.turning_radius = turning_radius
self.image = image
self.rect = self.image.get_rect()
Vehicle.vehicleCount = Vehicle.vehicleCount + 1
def displayAmount():
print ("Total number of Vehicle enteries: ", Vehicle.vehicleCount)
def displayVehicle(self):
print ("max speed: ", self.max_speed, "acceleration: ", self.acceleration, "turning radius: ", self.turning_radius)
def checkCollision(self, sprite2):
col = pygame.sprite.collide_rect(self, sprite2)
if col == True:
print ("True")
Here is an example of one of my vehicle objects being defined:
sportscar = Vehicle(4.5, 0.2, 2.01, sportsimage)
I am checking if the vehicles have intersecting by running the following line in the main game loop:
choice1.checkCollision(choice2)
However, when I run the program, the console outputs "True" constantly, even when the vehicles aren't touching. Does anyone know where I have gone wrong with this? Thanks.

Python: How do I detect visible shape detection in Tkinter

I am new to Python and I have a program that has 2 classes, one is essentially a rectangle and the other is essentially a circle. I am drawing them using the Canvas in Tkinter in the way below:
def draw(self):
self.canvas.delete("all")
self.rect.draw(self.canvas)
self.ball.draw(self.canvas)
The Ball class has its location variables and diameter variables and the Rect class has its location and dimension variables.
I am wondering how I detect the collision between these two "shapes". I know that one was is to treat the Ball as a square and do basic rectangle collision but I would like to know how to be precise.
I was also wondering if there was anything similar in Python to the way shape collision can be done in Java. In my Java game I use the following code to detect collision between any 2 Shapes:
public boolean collisionCheck(Shape a, Shape b) {
Area aA = new Area(a);
Area aB = new Area(b);
aA.intersect(aB);
return !aA.isEmpty();
}
Is there anything similar to this simple solution in Python?
And if not how would I go about circle-rectangle collision in Python?
Thank you for any help
I managed to figure this out using a method that Tkinter's Canvas object has. Every time something is drawn using Canvas it is given an ID. So as long as you record that ID somewhere you can use the find_overlapping method that the Canvas object has.
Say you have an object, in my case a custom Platform object, that keeps the ID stored in a variable. I did so like this:
def draw_platform(self, canvas): #Located in the Platform Class
self.ID = canvas.create_rectangle(self.x, self.y, self.x+self.w, self.y+self.h)
Now I can use this ID to determine if there are any object overlapping it.
def check_collision(self, plat, other_plat):
result = self.canvas.find_overlapping(plat.x, plat.y, plat.x + plat.w, plat.y + plat.h)
for i in result:
if i == other_plat.ID:
return True
return False
result returns a tuple of the ID's that are located within the rectangle bounds entered into find_overlapping. You can than loop through the tuple to see if any of the ID's match your other shape.
This works great for Rectangle-Rectangle collision and Circle-Rectangle collision.

Create a lot of objects and delete them

so i'm kinda new to programming, but for now with python and pygame i'm trying to create a small game. It is quite simple, the player will move around dodging small projectiles. However i'm having trouble creating a lot of objects, for example i need to randomly generate a position and a speed for a new projectile, and how do i create many objects like that, plus when they actually go 'out of the screen' they should disapear.
So I also need to delete them. My first idea was to create a list of objects, I and a loop that would move them one by one before updating the screen, but how do i create new objects with different names while I don't know how many projectiles will be on the screen, it should be random.
class Projectiles:
ProjectilesCount = 0
def __init__(self, x, y, speed):
self.pos = (x,y)
self.speed = speed
Projectiles.ProjectilesCount += 1
def moveProj(self):
x, y = self.pos
x -= self.speed
self.pos = (x,y)
pygame.draw.line(DISPLAY, WHITE, self.pos, (x,y+self.SIZE), self.SIZE)
bullet = Projectiles(500,200,5)
bullet.SIZE = SIZE
while true:
# some stuff
bullet.moveProj()
pygame.display.update()
fpsClock.tick(FPS)
This is the class i use for now (it just goes left) and it works for just one projectile.
You want a list:
list_of_bullets = []
for i in range(100):
list_of_bullets.append(Projectiles(...))
Use dictionaries. A list will work, but when using objects where the order is not important use dictionaries. Dictionaries also perform better when iterating through lots of data within them. Use some code similar to below...
bulletdict = {}
#This is a list because we can change the value within a function without returning it
#You could also use a global variable instead of a list
bulletcount = [0]
def SpawnBullet(bulletdict,bulletcount):
bulletdict[bulletcount] = Projectiles
bulletcount[0] += 1
The key will be a number and the value will be the bullet itself. To iterate through the dictionary to update stuff do...
for item in bulletdict:
bulletdict[item].moveproj(...)
If you need to remove stuff use code similar to this. I usually have 'checkDelete' functions inside my objects that I can call to check to see if we should remove them. This is used for things like deleting objects if they get off the screen or collide with something.
def deleteObjects(objectdict):
deletelist = []
for item in objectdict:
if objectdict[item].checkdelete() == True:
deletelist.append(item)
for item in deletelist:
del objectdict[item]
This allows for easy use and iteration of your objects. You can always tell the last spawned object because it will have the highest number as the key. This key number will also tell you the total number of spawned objects if you so need it.
I hope this helps you and good luck making your game.

Categories

Resources