Trying to create simple jump game in scratch found a bug that I can't figure out - game-development

Here is the link to the game so you can see the code..
https://scratch.mit.edu/projects/668072441
I am utterly confused the current setup uses blocks but I have tried dozens of configurations and none of them are working. Goal of the game is when the dog hits the black line (both are sprites) it ups the score by one and resets the dog this part works but when the dog hits cat it's supposed to broadcast the score and end the game. Then I am going to have the cat sprite say the final score later after I figure this out. But it doesn't end the game and I can't figure out why

The reason it isn't working is because of the block that says:
[glide (pick random (1) to (1.4)) seconds to x: (-240) y: (-100)]
The scripts below it won't be executed until the block finishes. At that point, the dog will be past the cat, so contact won't be detected. The fix is pretty simple: simply take the two if loops and move them into a single, different forever loop, like this:
when flag clicked:
forever:
if (touching (Sprite1)) then:
End Game
if (touching (Line)) then:
Score

Related

Roblox tds game

Im making a tower defense game in roblox and im wondering how to script towers having special effects when they hit a zombie, for example, freeze, slowness, poison etc. And how to make specific zombies immune to some of these effects.
What you could do is put a script in the zombie that can interpret what tower hit it and decide if it should deal damage or effects or something like that.
i would just have some numvalues inside the zombie and when u hit it change the value up 1 point and have another script in the value which will activate the effect and once the effect has been activated it removes 1 from the value.
u can change this around to fit the different effects so for a bleed effect you can name the value bleed and in the damage script when you hit a enemy it will findfirstchild for bleed and add 1 to the value and have another script within the value doing the bleed damage which would be something like
local bleedvalue = script.parent.value
local enemytype = script.parent.parent:waitforchild("humanoid")
while wait(tick speed) do
if script.parent.value < 0 then
bleedvalue = bleedvalue - (ammount you want removed per tick)
enemytype.health = enemytype.health - (damage ammount and health can be changed out for speed or can straight up just anchor the zombie for a freeze)
end
end
this was just off the top of my head so sorry if its wrong but i hope i helped anyone who may be seeking a alternative

Player doesn't spawn correctly in procedural generated map

I've followed "Procedural Generation in Godot: Dungeon Generation" by KidsCanCode #https://www.youtube.com/watch?v=o3fwlk1NI-w and find myself unable to debug the current problem.
This specific commit has the code, but I'll try to explain in more detail bellow.
My main scene has a Camera2D node, a generic Node2D calles Rooms and a TileMap, everything is empty.
When the script starts, it runs a
func make_room(_pos, _size):
position = _pos
size = _size
var s = RectangleShape2D.new()
s.custom_solver_bias = 0.5
s.extents = size
$CollisionShape2D.shape = s
A few times and it fills $Rooms using .add_child(r) where r is a instance of the node that has the make_room() function. It will then iterate over $Rooms.get_children() a few times to create a AStar node to link all the rooms:
The magic comes when make_map() is called after afterwards, it fills the map with non-walkable blocks and then it carves the empty spaces, which works fine too:
There is a find_start_room() that is called to find the initial room, it also sets a global variable to the Main script start_room, which is used to write 'Start' on the map using draw_string(font, start_room.position - Vector2(125,0),"start",Color(3,4,8))
When I hit 'esc' it runs this simple code to instance the player:
player = Player.instance()
add_child(player)
player.position = start_room.position + Vector2(start_room.size.x/2, start_room.size.y/2)
play_mode = true
The problem comes when spawning the player. I tried doing some 'blind' fixing, such as adding or subtracting a Vector2(start_room.size.x/2, start_room.size.y/2) to player.position to see if I could make it fall within the room, to no avail.
Turning to the debugger didn't help, as the positions expressed by the variable inspectors don't seem to mean anything.
I tried implementing a simple 'mouse click print location':
print("Mouse Click/Unclick at: ", event.position)
print("Node thing",get_node("/root/Main/TileMap").world_to_map(event.position))
And also a 'start_room' print location:
print(get_node("/root/Main/TileMap").world_to_map(start_room.position))
And a when player moves print location, written directly into the Character script:
print(get_node("/root/Main/TileMap").world_to_map(self.position))
Getting results like the ones bellow:
Mouse Click/Unclick at: (518, 293)
Node thing(16, 9)
(-142, 0)
(-147, -3)
So, the player doesn't spawn on the same position as the start_room and the mouse position information is not the same as anything else.
Why is the player now spawning correctly? How can I debug this situation?
EDIT1: User Theraot mentioned about how the RigidBody2D is doing some weird collisions, and from what I understood, changing their collision behavior should fix the whole thing.
There's a section on the code that -after generating the random rooms- it removes some of the rooms like this:
for room in $Rooms.get_children():
if randf() < cull:
room.queue_free()
else:
room.mode = RigidBody2D.MODE_STATIC
room_positions.append(Vector3(room.position.x, room.position.y, 0))
From what I understand, if the room is randomly selected it will be deleted using queue_free() OR it will be appended to a room_positions for further processing. This means if I shift all the rooms to a different collision layer, the player/character instance would be alone with the TileMap on the same collision layer.
So I just added a simple room.collision_layer = 3 changing this section of the code to
for room in $Rooms.get_children():
if randf() < cull:
room.queue_free()
else:
room.mode = RigidBody2D.MODE_STATIC
room.collision_layer = 3
room_positions.append(Vector3(room.position.x, room.position.y, 0))
It doesn't seem to have changed anything, the player still spawns outside the room.
Do you see the rooms spread outwards?
You didn't write code to move the rooms. Sure, the code gives them a random position. But even if you set their position to Vector2.ZERO they move outwards, avoiding overlaps.
Why? Because these rooms are RigidBody2D, and they do push other physics objects. Such as other rooms or the player character.
That's the problem: These rooms are RigidBody2D, and you put your KinematicBody2D player character on top of one of them. The RigidBody2D pushes it out.
The tutorial you followed is exploiting this behavior of RigidBody2Ds to spread the rooms. However you don't need these RigidBody2D after you are done populating your TileMap.
Instead, you can store the start position in a variable for later placing the player character (you don't need offsets - by the way - the position of the room is the center of the room), and then remove the RigidBody2Ds. If you want to keep the code that writes the text, you would also have to modify it, so it does not fail when the room no longer exists.
Alternatively, you can edit their collision layer and mask so they don't collide with the player character (or anything for that matter, but why would you want these RigidBody2Ds that collide with nothing?).
Addendum post edit: Collision layers and mask don't work as you expect.
First of all, the collision layer and mask are flags. The values of the layers are powers of two (1, 2, 4, 8...). So, when you set it to 3, it is the layer 1 plus the layer 2. So it still collides with a collision mask of 1.
And second, even if you changed the collision layer of the rooms to 2 (so it does not match the collision mask of 1 that the player character has). The player character still has a layer 1 which match the collision mask of the rooms.
See also the proposal Make physics layers and masks logic simple and consistent.
Thus, you would need to change the layer and mask. Both. in such way that they don't collide. For example, you can set layer and mask to 0 (which disable all collisions). The algorithm that populates the TileMap does not use the layer and mask.

How to create a binary window for an event in Python

I have some sensor data and I know when the main event happens, but there's some noise before and after this event, and so I want to create a binary window where I can then just through away all the non important information.
Here is a toy example.
eg=pd.DataFrame({"Seconds":[0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5],
"Event":[0,0,1,0,0,0,0,1,0,0,0,1],
"Start":[0,1,0,0,0,0,1,0,0,0,1,0],
"End": [0,0,0,1,0,0,0,0,1,0,0,0],
"Want": [0,1,1,1,0,0,1,1,1,0,1,1]})
I have generated my start and end with shifting. What I cannot seem to create in Python is my Want. The start and the end are more than 1 row away from the event, albeit they are fixed intervals.
In excel I am able to create a 3 nested that effectively does the following:
fup_bottom["Want"]=np.where(fup_bottom.End==1,0,
np.where(fup_bottom.Start==1,1,
np.where(fup_bottom.Want.shift(1)==1,1,0)))
In python this doesn't work because the "Want" doesn't exist yet.
I have tried recording the seconds where Start is 1 and forward filling, and then similarly where End is one and backward filling. However, this leads to Want always being 1 after the first event.
I greatly appreciate any help on this. I've been trying to figure this out for a couple of hours and am stuck.
J

Confusion with writing a game loop

I'm working on a 2D video game framework, and I've never written a game loop before. Most frameworks I've ever looked in to seem to implement both a draw and update methods.
For my project I implemented a loop that calls these 2 methods. I noticed with other frameworks, these methods don't always get called alternating. Some frameworks will have update run way more than draw does. Also, most of these types of frameworks will run at 60FPS. I figure I'll need some sort of sleep in here.
My question is, what is the best method for implementing this type of loop? Do I call draw then update, or vice versa? In my case, I'm writing a wrapper around SDL2, so maybe that library requires something to be setup in a certain way?
Here's some "pseudo" code I'm thinking of for the implementation.
loop do
clear_screen
draw
update
sleep(16.milliseconds)
break if window_is_closed
end
Though my project is being written in Crystal-Lang, I'm more looking for a general concept that could be applied to any language.
It depends what you want to achieve. Some games prefer the game logic to run more frequently than the frame rate (I believe Source games do this), for some games you may want the game logic to run less frequently (the only example of this I can think of is the servers of some multiplayer games, quite famously Overwatch).
It's important to consider as well that this is a question of resolution, not speed. A game with logic rate 120 and frame rate 60 is not necessarily running at x2 speed, any time critical operations within the game logic should be done relative to the clock*, not the tic rate, or your game will literally go into slow motion if the frames take too long to render.
I would recommend writing a loop like this:
loop do
time_until_update = (update_interval + time_of_last_update) - current_time
time_until_draw = (draw_interval + time_of_last_draw) - current_time
work_done = false
# Update the game if it's been enough time
if time_until_update <= 0
update
time_of_last_update = current_time
work_done = true
end
# Draw the screen if it's been enough time
if time_until_draw <= 0
clear_screen
draw
time_of_last_draw = current_time
work_done = true
end
# Nothing to do, sleep for the smallest period
if work_done == false
smaller = time_until_update
if time_until_draw < smaller
smaller = time_until_draw
end
sleep_for(smaller)
end
# Leave, maybe
break if window_is_closed
end
You don't want to wait for 16ms every frame otherwise you might end up over-waiting if the frame takes a non-trivial amount of time to complete. The work_done variable is so that we know whether or not the intervals we calculated at the start of the loop are still valid, we may have done 5ms of work, which would throw our sleeping completely off so in that scenario we go back around and calculate fresh values.
* You may want to abstractify the clock, using the clock directly can have some weird effects, for example if you save the game and you save the last time you used a magical power as a clock time, it will instantly come off cooldown when you load the save, as that is now minutes, hours or even days in the past. Similar issues exist with the process being suspended by the operating system.

Check every value in a list in TI-Basic

I'm writing a snake game in TI-Basic, and every time I move I need to see if the head of the snake has hit any point in the tail. The tail is stored as a circular list-based queue, and I can add the beginning and end in constant time.
The only hard part is that I have to do something similar to this on every iteration:
(S = Size of the list)
For(I,1,S)
If X=LX(I) and Y=LY(I)
Then
Disp "GAME OVER"
Return
End
End
It's a fairly short loop, but it takes forever even on a list of 10 items. I tried the sequence way:
If sum(seq(X=LX(I) and Y=LY(I),I,1,S))
...
The only other optimization I can think of is to not check values for N to N+2 (because the first part of your tail that's possible to hit is at N+3), but that just puts off the problem after 4 points, and having the game unplayable with 14 points is no better than being unplayable after 10 points.
Using assembly isn't an option because I don't have a link cable (or the desire to write assembly).
Never used TI-Basic...
but how about also storing a 2D array of the game board. Each element in that array indicates if the snake is present. When you move forward, set the value of the array at the head point, and clear the value at the old tail end point. Then to test for collision, you can just do one lookup into the 2D array.
The entire block:
For(I,1,S)
If X=LX(I) and Y=LY(I)
Then
Disp "GAME OVER"
Return
End
End
can be replaced with:
If sum(X=LX and Y=LY)
Then
Disp "Game Over"
Return
End
X=LX applies the test piecewise to every element of LX, and the same goes for Y=LY. The sum() checks if there is a 1 in the intersection of the two lists.
What I did, when I was programming Snake, was to check if the pixel in front of the snake was on. If it was, I would check if this pixel is the "food" pixel, otherwise, the game would stop.
Example, with I and J being head and tail positions, (F, G) being the direction of the snake, and (M, N) being the food.
if Pxl-Test(I+F, J+G) #pixel in front of snake
then
if I+F=M and J+G=N
stop
end
Much more memory-conservant than a 2D array.